diffing 0.2.1 → 0.4.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 (436) hide show
  1. package/README.md +169 -3
  2. package/dist/{cli-agent-BNwY5lZE.mjs → cli-agent-B4hU6Xay.mjs} +58 -5
  3. package/dist/{cli-agent-CbzXDSSF.mjs → cli-agent-B_PHd635.mjs} +58 -5
  4. package/dist/{cli-agent-ZAkixf4c.mjs → cli-agent-KxNAFIPf.mjs} +6 -2
  5. package/dist/cli-gh-CDGSpndZ.mjs +147 -0
  6. package/dist/cli-gh-abs-IJrz.mjs +147 -0
  7. package/dist/cli.mjs +1214 -56
  8. package/dist/client/assets/{angular-html-DsssUIMZ.js → angular-html-BVFBJbbm.js} +1 -1
  9. package/dist/client/assets/{angular-ts-dTg-sJ77.js → angular-ts-CbJB4bNJ.js} +1 -1
  10. package/dist/client/assets/{apl-C1yUKbqz.js → apl-MzqTwOQT.js} +1 -1
  11. package/dist/client/assets/arc-DkYz3FVO.js +1 -0
  12. package/dist/client/assets/architecture-7EHR7CIX-BM5HxebS.js +1 -0
  13. package/dist/client/assets/architectureDiagram-3BPJPVTR-CU3k1-_g.js +36 -0
  14. package/dist/client/assets/array-CkF66D10.js +1 -0
  15. package/dist/client/assets/{astro-BI07ha2y.js → astro-DDblGxmh.js} +1 -1
  16. package/dist/client/assets/{blade-DkzUGffS.js → blade-DlgT3iuV.js} +1 -1
  17. package/dist/client/assets/blockDiagram-GPEHLZMM-1lwkHRY_.js +132 -0
  18. package/dist/client/assets/{bsl-Dx5tFn3i.js → bsl-BrHd4RA2.js} +1 -1
  19. package/dist/client/assets/{c-KkuqqOvW.js → c-BL61MF4M.js} +1 -1
  20. package/dist/client/assets/c4Diagram-AAUBKEIU-BPBjnNM8.js +10 -0
  21. package/dist/client/assets/{cairo-wCCQTdA9.js → cairo-BDZ6TRZS.js} +1 -1
  22. package/dist/client/assets/channel-BX6tZjG6.js +1 -0
  23. package/dist/client/assets/chunk-2J33WTMH-C_SASPYW.js +1 -0
  24. package/dist/client/assets/chunk-3OPIFGDE-CTcbOBts.js +62 -0
  25. package/dist/client/assets/chunk-4BX2VUAB-BipHnfY4.js +1 -0
  26. package/dist/client/assets/chunk-4EGX6M5U-C70lfA2p.js +1 -0
  27. package/dist/client/assets/chunk-55IACEB6-BzJYLlnc.js +1 -0
  28. package/dist/client/assets/chunk-5DO6E6H7-PprNUwlI.js +1 -0
  29. package/dist/client/assets/chunk-5ZQYHXKU-CorupEGf.js +2 -0
  30. package/dist/client/assets/chunk-727SXJPM-Cqjzb4FZ.js +206 -0
  31. package/dist/client/assets/chunk-AQP2D5EJ-DcaAmtSe.js +231 -0
  32. package/dist/client/assets/chunk-BR22UD5L-D8XCYMy9.js +1 -0
  33. package/dist/client/assets/chunk-BSJP7CBP-CiBjSxwv.js +1 -0
  34. package/dist/client/assets/chunk-CSCIHK7Q-BTbf6qN3.js +124 -0
  35. package/dist/client/assets/chunk-FHYWG6QK-CcHPrHH1.js +1 -0
  36. package/dist/client/assets/chunk-FMBD7UC4-BA8_ZS2e.js +15 -0
  37. package/dist/client/assets/chunk-KSCS5N6A-ChcT2GOp.js +10 -0
  38. package/dist/client/assets/chunk-L5ZTLDWV-BjzpE0xm.js +1 -0
  39. package/dist/client/assets/chunk-LZXEDZCA-Bu0azrf_.js +2 -0
  40. package/dist/client/assets/chunk-MPE355IW-Bf9yHfDS.js +1 -0
  41. package/dist/client/assets/chunk-MZUSXYTE-CnUIUKI4.js +1 -0
  42. package/dist/client/assets/chunk-N66VUXT2-ahAf9GvV.js +1 -0
  43. package/dist/client/assets/chunk-ND2GUHAM-Co55RNsd.js +1 -0
  44. package/dist/client/assets/chunk-NNHCCRGN-DHF3V75i.js +159 -0
  45. package/dist/client/assets/chunk-NZK2D7GU-CtPYeO8_.js +1 -0
  46. package/dist/client/assets/chunk-O5CBEL6O-CzRKb_Hn.js +70 -0
  47. package/dist/client/assets/chunk-PUPMXCY4-D0KKIhut.js +1 -0
  48. package/dist/client/assets/chunk-QZHKN3VN-BCSN705V.js +1 -0
  49. package/dist/client/assets/chunk-UIBZB4QT-TYsZ_c8u.js +1 -0
  50. package/dist/client/assets/chunk-WCWK7LTN-Dj8SfnMU.js +1 -0
  51. package/dist/client/assets/chunk-WU5MYG2G-xPWDnrji.js +1 -0
  52. package/dist/client/assets/chunk-XPW4576I-CYH9wUok.js +32 -0
  53. package/dist/client/assets/classDiagram-4FO5ZUOK-7xfBUC5E.js +1 -0
  54. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CFM5yYso.js +1 -0
  55. package/dist/client/assets/{cobol-DRh7-jLi.js → cobol-D37UDAkO.js} +1 -1
  56. package/dist/client/assets/{coffee-wR_ZAh9a.js → coffee-NCjhDwWZ.js} +1 -1
  57. package/dist/client/assets/cose-bilkent-S5V4N54A-B8RnQ-yF.js +1 -0
  58. package/dist/client/assets/{cpp-OD_qyywn.js → cpp-CQUNgUz4.js} +1 -1
  59. package/dist/client/assets/{crystal-E4ahAddE.js → crystal-DGHLJtZ_.js} +1 -1
  60. package/dist/client/assets/{css-2NgE_uxz.js → css-xCgEbp_3.js} +1 -1
  61. package/dist/client/assets/cytoscape.esm-B7MQoI9k.js +321 -0
  62. package/dist/client/assets/dagre-BM42HDAG-CvmQMXPT.js +4 -0
  63. package/dist/client/assets/dagre-DAhKikc0.js +1 -0
  64. package/dist/client/assets/defaultLocale-B_TxGd0k.js +1 -0
  65. package/dist/client/assets/diagram-2AECGRRQ-wIyWTlXo.js +43 -0
  66. package/dist/client/assets/diagram-5GNKFQAL-BLMMWtHj.js +10 -0
  67. package/dist/client/assets/diagram-KO2AKTUF-Duz_hHky.js +3 -0
  68. package/dist/client/assets/diagram-LMA3HP47-CftQIrJ1.js +24 -0
  69. package/dist/client/assets/diagram-OG6HWLK6-7odjt2qL.js +24 -0
  70. package/dist/client/assets/dist-PmPhNea3.js +1 -0
  71. package/dist/client/assets/{edge-8mbscxxD.js → edge-C6_UFojU.js} +1 -1
  72. package/dist/client/assets/{elixir-CJv1b3Q6.js → elixir-B12MoaTY.js} +1 -1
  73. package/dist/client/assets/{elm-DUPzqZ9H.js → elm-C80KxC_R.js} +1 -1
  74. package/dist/client/assets/erDiagram-TEJ5UH35-DOeyf617.js +85 -0
  75. package/dist/client/assets/{erb-ssvEF26z.js → erb-DqelkF7l.js} +1 -1
  76. package/dist/client/assets/{erlang-CtK0kQ6z.js → erlang-cuhwpmsu.js} +1 -1
  77. package/dist/client/assets/eventmodeling-FCH6USID-hlXE2E34.js +1 -0
  78. package/dist/client/assets/flowDiagram-I6XJVG4X-BJX7W8r0.js +162 -0
  79. package/dist/client/assets/{fortran-fixed-form-DBM4e0_k.js → fortran-fixed-form-DWr0EnJn.js} +1 -1
  80. package/dist/client/assets/{fsharp-CmzzGQLe.js → fsharp-CQ5iYSPA.js} +1 -1
  81. package/dist/client/assets/ganttDiagram-6RSMTGT7-CFWnCca0.js +292 -0
  82. package/dist/client/assets/{gdresource-B_wbPqHd.js → gdresource-CN-lsNu5.js} +1 -1
  83. package/dist/client/assets/{git-commit-1z4D6NzL.js → git-commit-6e79eN7Q.js} +1 -1
  84. package/dist/client/assets/{git-rebase-DiWIK1Oa.js → git-rebase-7L4r_tbx.js} +1 -1
  85. package/dist/client/assets/gitGraph-WXDBUCRP-D_3ZhTam.js +1 -0
  86. package/dist/client/assets/gitGraphDiagram-PVQCEYII-oNErRHPR.js +106 -0
  87. package/dist/client/assets/{glimmer-js-DrHg6AuA.js → glimmer-js-8OQAbTGs.js} +1 -1
  88. package/dist/client/assets/{glimmer-ts-wQSGOa8A.js → glimmer-ts-3IyQiCHC.js} +1 -1
  89. package/dist/client/assets/{glsl-OY27QGY0.js → glsl-Bi_bzGJK.js} +1 -1
  90. package/dist/client/assets/graphlib-DBdw4opr.js +1 -0
  91. package/dist/client/assets/{graphql-CSWSqe6f.js → graphql-YcGxsBfT.js} +1 -1
  92. package/dist/client/assets/{hack-Bi1v624Q.js → hack-C9IpUqi6.js} +1 -1
  93. package/dist/client/assets/{haml-CX94zV9m.js → haml-YWDwVGeX.js} +1 -1
  94. package/dist/client/assets/{handlebars-C1j6wnjG.js → handlebars-zyG7ocdI.js} +1 -1
  95. package/dist/client/assets/{html-BcAjMlB7.js → html-CHYhpzfH.js} +1 -1
  96. package/dist/client/assets/{html-derivative-DcEpOzdx.js → html-derivative-BhgSILdB.js} +1 -1
  97. package/dist/client/assets/{http-BBxxSc6S.js → http-BPv6bUpq.js} +1 -1
  98. package/dist/client/assets/{hurl-CpKRNTz4.js → hurl-CpohSten.js} +1 -1
  99. package/dist/client/assets/{hxml-DC4KwKt2.js → hxml-nwJci6H5.js} +1 -1
  100. package/dist/client/assets/index-BIrpcT6-.js +3922 -0
  101. package/dist/client/assets/index-CMyunQt6.css +1 -0
  102. package/dist/client/assets/info-J43DQDTF-CAllC7mK.js +1 -0
  103. package/dist/client/assets/infoDiagram-5YYISTIA-D1xM4RZP.js +2 -0
  104. package/dist/client/assets/init-Ce66tIvf.js +1 -0
  105. package/dist/client/assets/ishikawaDiagram-YF4QCWOH-7DsxXa1L.js +70 -0
  106. package/dist/client/assets/{java-CFUlLvAA.js → java-Bt4sAY2m.js} +1 -1
  107. package/dist/client/assets/{javascript-C-HnT3sE.js → javascript-DZjI42QZ.js} +1 -1
  108. package/dist/client/assets/{jinja-CPU8RwNP.js → jinja-D2zTW07t.js} +1 -1
  109. package/dist/client/assets/{jison-CW0TBQOs.js → jison-Dz-ndIM5.js} +1 -1
  110. package/dist/client/assets/journeyDiagram-JHISSGLW-C_A1TmoL.js +139 -0
  111. package/dist/client/assets/{json-qUjlNuEJ.js → json-Ykn4LhOH.js} +1 -1
  112. package/dist/client/assets/{jsx-KWeo60kf.js → jsx-Ce8SKNSt.js} +1 -1
  113. package/dist/client/assets/{julia-CnJB8y2e.js → julia-DlfibiGU.js} +1 -1
  114. package/dist/client/assets/{just-Do22d9PP.js → just-CT2PIeY2.js} +1 -1
  115. package/dist/client/assets/kanban-definition-UN3LZRKU-ccKLE8Df.js +89 -0
  116. package/dist/client/assets/katex-eRFNlMh0.js +257 -0
  117. package/dist/client/assets/{latex-CCPgzvKn.js → latex-Dkfo8_p4.js} +1 -1
  118. package/dist/client/assets/line-BbqJI7bZ.js +1 -0
  119. package/dist/client/assets/linear-B7c0dSOq.js +1 -0
  120. package/dist/client/assets/{liquid-B9btdZoI.js → liquid-dWmg5egV.js} +1 -1
  121. package/dist/client/assets/{lua-IFRifurW.js → lua-6hNhLpj8.js} +1 -1
  122. package/dist/client/assets/{marko-CCaVBFq1.js → marko-DTVuQVoJ.js} +1 -1
  123. package/dist/client/assets/{mdc-BtbnOLUc.js → mdc-LbJVW6cj.js} +1 -1
  124. package/dist/client/assets/mermaid-parser.core-f-eKVdX9.js +4 -0
  125. package/dist/client/assets/mermaid.core-ClMOD6O3.js +9 -0
  126. package/dist/client/assets/mindmap-definition-RKZ34NQL-vaLTR09L.js +96 -0
  127. package/dist/client/assets/{nextflow-CApkvBGW.js → nextflow-DSfydIxt.js} +1 -1
  128. package/dist/client/assets/{nginx-BkbFZHVt.js → nginx-BvMTgdwH.js} +1 -1
  129. package/dist/client/assets/{nim-2uCd5j65.js → nim-BdGYhiTu.js} +1 -1
  130. package/dist/client/assets/ordinal-5ziJS8mo.js +1 -0
  131. package/dist/client/assets/packet-YPE3B663-Dy58IAiO.js +1 -0
  132. package/dist/client/assets/path-g3G46IZB.js +1 -0
  133. package/dist/client/assets/{perl-C4ixqSNT.js → perl-DamEOAxn.js} +1 -1
  134. package/dist/client/assets/{php-DJ8WOtcI.js → php-DtubpAAy.js} +1 -1
  135. package/dist/client/assets/pie-LRSECV5Y-FXFFfdz2.js +1 -0
  136. package/dist/client/assets/pieDiagram-4H26LBE5-yuTkGKaM.js +30 -0
  137. package/dist/client/assets/{pug-BOaafhT5.js → pug-CMYtl1BN.js} +1 -1
  138. package/dist/client/assets/{qml-CURE-1y4.js → qml-D76DCV4U.js} +1 -1
  139. package/dist/client/assets/quadrantDiagram-W4KKPZXB-Db00tlGp.js +7 -0
  140. package/dist/client/assets/{r-CPWmgzo3.js → r-gMTLVmYP.js} +1 -1
  141. package/dist/client/assets/radar-GUYGQ44K-BKTzSQ68.js +1 -0
  142. package/dist/client/assets/{razor-DH83VP_d.js → razor-1oOg77PO.js} +1 -1
  143. package/dist/client/assets/{regexp-BXVWi-t_.js → regexp-BJzbycG8.js} +1 -1
  144. package/dist/client/assets/requirementDiagram-4Y6WPE33-CwCGFaVe.js +84 -0
  145. package/dist/client/assets/rough.esm-BBrzuQ0N.js +1 -0
  146. package/dist/client/assets/{rst-Bbxxs6E2.js → rst-Be7RtxcU.js} +1 -1
  147. package/dist/client/assets/{ruby-C-TuWES4.js → ruby-oyNd3WUZ.js} +1 -1
  148. package/dist/client/assets/sankeyDiagram-5OEKKPKP-D78nH-eA.js +40 -0
  149. package/dist/client/assets/{sas-njzNYNOq.js → sas-Bx8dCxcK.js} +1 -1
  150. package/dist/client/assets/{scss-D2i6rHB8.js → scss-DzZEPh1d.js} +1 -1
  151. package/dist/client/assets/sequenceDiagram-3UESZ5HK-CEy9mjHg.js +162 -0
  152. package/dist/client/assets/{shaderlab-DXAhMdPo.js → shaderlab-CbbQwRPF.js} +1 -1
  153. package/dist/client/assets/{shellscript-D6Bxi40C.js → shellscript-t9s0AoBc.js} +1 -1
  154. package/dist/client/assets/{shellsession-Defxq-I6.js → shellsession-NczJO6Io.js} +1 -1
  155. package/dist/client/assets/{soy-D0GKXrtT.js → soy-Dl6InSac.js} +1 -1
  156. package/dist/client/assets/{sparql-BdcL8cbr.js → sparql-DEoxFJ5d.js} +1 -1
  157. package/dist/client/assets/{sql-BRW_ADkU.js → sql-DXkZEc28.js} +1 -1
  158. package/dist/client/assets/src-DCIMHd9M.js +1 -0
  159. package/dist/client/assets/{stata-w7w59F48.js → stata-DmpUDP7M.js} +1 -1
  160. package/dist/client/assets/stateDiagram-AJRCARHV-Cz0qtN4R.js +1 -0
  161. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-Dye5cILT.js +1 -0
  162. package/dist/client/assets/{surrealql-O-lLuqz7.js → surrealql-BAZp4tA6.js} +1 -1
  163. package/dist/client/assets/{svelte-DN3DR5-t.js → svelte-DXBMAgu7.js} +1 -1
  164. package/dist/client/assets/{templ-CJ2JFoia.js → templ-CF-yfRM7.js} +1 -1
  165. package/dist/client/assets/{tex-CpWrf5g9.js → tex-D5tGX-j9.js} +1 -1
  166. package/dist/client/assets/timeline-definition-PNZ67QCA-B6_u5aFI.js +120 -0
  167. package/dist/client/assets/treeView-BLDUP644-DtjHwb6x.js +1 -0
  168. package/dist/client/assets/treemap-LRROVOQU-GqTXzMFU.js +1 -0
  169. package/dist/client/assets/{ts-tags-CZ6Af6Pe.js → ts-tags-DWMVxoO1.js} +1 -1
  170. package/dist/client/assets/{tsx-gIUSpRih.js → tsx-C6QVlWvX.js} +1 -1
  171. package/dist/client/assets/{twig-DwZINhmw.js → twig-DKFN0Lvm.js} +1 -1
  172. package/dist/client/assets/{typescript-Dj2aMECR.js → typescript-DVfrnfSW.js} +1 -1
  173. package/dist/client/assets/vennDiagram-CIIHVFJN-C_-TQFos.js +34 -0
  174. package/dist/client/assets/{vue-B5K0aWrP.js → vue-BCLQ-g1T.js} +1 -1
  175. package/dist/client/assets/{vue-html-DKGgrypd.js → vue-html-Ddr0JbE-.js} +1 -1
  176. package/dist/client/assets/{vue-vine-B5iDYTCh.js → vue-vine-CX36RUs5.js} +1 -1
  177. package/dist/client/assets/wardley-L42UT6IY-pROVAAhW.js +1 -0
  178. package/dist/client/assets/wardleyDiagram-YWT4CUSO-BJQg7Pb-.js +78 -0
  179. package/dist/client/assets/{xml-CbTzxfc-.js → xml-FnMA1W8C.js} +1 -1
  180. package/dist/client/assets/{xsl-Dj-Be6nx.js → xsl-CLduN3zs.js} +1 -1
  181. package/dist/client/assets/xychartDiagram-2RQKCTM6-1Ux8tle4.js +7 -0
  182. package/dist/client/assets/{yaml-rTK8uEjh.js → yaml-B6hNfHm7.js} +1 -1
  183. package/dist/client/index.html +2 -2
  184. package/dist/{mcp-CE77qfjx.mjs → mcp-BWeWR4yd.mjs} +2 -1
  185. package/dist/{mcp-CFeE13n-.mjs → mcp-DNZQvKKF.mjs} +45 -1
  186. package/dist/{mcp-SGCrfYGo.mjs → mcp-DO4zfNZX.mjs} +45 -1
  187. package/dist/plan-format-DVnF8xrq.mjs +126 -0
  188. package/dist/plan-format-f62JWFI-.mjs +117 -0
  189. package/dist/plan-format-mSDtsPcC.mjs +132 -0
  190. package/dist/{server-lock-B4crz9-_.mjs → server-lock-D73NKKbn.mjs} +267 -133
  191. package/dist/{server-lock-DpCrvL-Z.mjs → server-lock-Dj9fG9md.mjs} +246 -122
  192. package/package.json +26 -14
  193. package/dist/cli-agent-BLPX3oOP.mjs +0 -443
  194. package/dist/cli-agent-Cfuy9fLC.mjs +0 -179
  195. package/dist/cli-agent-CtNivjQW.mjs +0 -179
  196. package/dist/cli-agent-DZBvZoXZ.mjs +0 -179
  197. package/dist/cli-agent-DsqbS3n7.mjs +0 -443
  198. package/dist/cli-agent-Vbs-ePHv.mjs +0 -443
  199. package/dist/cli-agent-WzJPMH52.mjs +0 -174
  200. package/dist/cli-agent-uYUoCA4X.mjs +0 -179
  201. package/dist/client/assets/index-Bwv7BWUp.js +0 -3959
  202. package/dist/client/assets/index-CoZyJYkw.css +0 -1
  203. package/dist/mcp-BQmH_By-.mjs +0 -119
  204. package/dist/mcp-CLgzC8_a.mjs +0 -119
  205. package/dist/mcp-D9E2HQZ9.mjs +0 -119
  206. package/dist/mcp-DKlThflu.mjs +0 -253
  207. package/dist/mcp-LVbLV17O.mjs +0 -119
  208. package/dist/mcp-nMwTAut3.mjs +0 -119
  209. package/dist/server-lock-BbiF7u3F.mjs +0 -493
  210. package/dist/server-lock-Bx9ixiF6.mjs +0 -575
  211. package/dist/server-lock-CAdqFSfl.mjs +0 -691
  212. package/dist/server-lock-DIkImokU.mjs +0 -487
  213. package/dist/server-lock-DbxpfF3j.mjs +0 -575
  214. package/dist/update-check-DJuFE9w6.mjs +0 -128
  215. package/dist/update-check-DSC02MWQ.mjs +0 -129
  216. package/dist/client/assets/{abap-CkQ0tsz-.js → abap-cWYhO34H.js} +0 -0
  217. package/dist/client/assets/{actionscript-3-DHm0ZfF4.js → actionscript-3-B80ndJsD.js} +0 -0
  218. package/dist/client/assets/{ada-DK_ua92Z.js → ada-C0C0SoYB.js} +0 -0
  219. package/dist/client/assets/{andromeeda-D2ccw8v4.js → andromeeda-Ch2kWS7s.js} +0 -0
  220. package/dist/client/assets/{apache-DXtpFu7o.js → apache-DBwBm4bB.js} +0 -0
  221. package/dist/client/assets/{apex-DlnRRWpl.js → apex-FcV7UxQi.js} +0 -0
  222. package/dist/client/assets/{applescript-CShk62ad.js → applescript-hQs8VNpS.js} +0 -0
  223. package/dist/client/assets/{ara-CWN-FDkm.js → ara-BOadBOZg.js} +0 -0
  224. package/dist/client/assets/{asciidoc-Bg-PM9Vn.js → asciidoc-BsfqiBck.js} +0 -0
  225. package/dist/client/assets/{asm-DKOhR24S.js → asm-C2vUqzqz.js} +0 -0
  226. package/dist/client/assets/{aurora-x-DpaEirL8.js → aurora-x-BHLqzt7j.js} +0 -0
  227. package/dist/client/assets/{awk-3ibKHffv.js → awk-D4e-eeZT.js} +0 -0
  228. package/dist/client/assets/{ayu-dark-ursiSH5k.js → ayu-dark-DCotN_ZT.js} +0 -0
  229. package/dist/client/assets/{ayu-light-DMjlrKmx.js → ayu-light-CKB6o_im.js} +0 -0
  230. package/dist/client/assets/{ayu-mirage-DZEMb75h.js → ayu-mirage-B38lW-C5.js} +0 -0
  231. package/dist/client/assets/{ballerina-xx7VNGxs.js → ballerina-BzvFqbha.js} +0 -0
  232. package/dist/client/assets/{bat-DGYsZ5wR.js → bat-CFyw2ERn.js} +0 -0
  233. package/dist/client/assets/{beancount-D_ATR1UV.js → beancount-a6Gsu5WX.js} +0 -0
  234. package/dist/client/assets/{berry-BqYMORfH.js → berry-C2jyz4Ah.js} +0 -0
  235. package/dist/client/assets/{bibtex-CQTBDajW.js → bibtex-Dyet-B83.js} +0 -0
  236. package/dist/client/assets/{bicep-CfNtxPrK.js → bicep-CghvUIvy.js} +0 -0
  237. package/dist/client/assets/{bird2-C0dUPe3I.js → bird2-nHigvs-R.js} +0 -0
  238. package/dist/client/assets/{c3-BUwZ5e3k.js → c3-9ZrcmAmr.js} +0 -0
  239. package/dist/client/assets/{cadence-C3OKDYrr.js → cadence-BPDgYNWy.js} +0 -0
  240. package/dist/client/assets/{catppuccin-frappe-CMnRXVZP.js → catppuccin-frappe-BY_2ofjk.js} +0 -0
  241. package/dist/client/assets/{catppuccin-latte-CqhXSjCC.js → catppuccin-latte-D6GXPBmA.js} +0 -0
  242. package/dist/client/assets/{catppuccin-macchiato-B6kneE0C.js → catppuccin-macchiato-BuW8_cyo.js} +0 -0
  243. package/dist/client/assets/{catppuccin-mocha-CP8YZpvj.js → catppuccin-mocha-znex9DPe.js} +0 -0
  244. package/dist/client/assets/{clarity-Crxe8gSr.js → clarity-Cmao5KSK.js} +0 -0
  245. package/dist/client/assets/{clojure-BuzOUPMr.js → clojure-D2dPuTkk.js} +0 -0
  246. package/dist/client/assets/{cmake-CCpZLdLI.js → cmake-DaqQuj4A.js} +0 -0
  247. package/dist/client/assets/{codeowners-Bo1VYpHz.js → codeowners-B748jmvc.js} +0 -0
  248. package/dist/client/assets/{codeql-Db01hzHE.js → codeql-CXb_8gHR.js} +0 -0
  249. package/dist/client/assets/{common-lisp-CMlJIc6Y.js → common-lisp-UZn9nc_5.js} +0 -0
  250. package/dist/client/assets/{coq-BlzBYp3f.js → coq-DtO6yBIf.js} +0 -0
  251. package/dist/client/assets/{csharp-kfNshAa7.js → csharp-C3YlYcLV.js} +0 -0
  252. package/dist/client/assets/{csv-Dr8ri5Nd.js → csv-BBwiVr0X.js} +0 -0
  253. package/dist/client/assets/{cue-jXfhyOwY.js → cue-ScBFXY5f.js} +0 -0
  254. package/dist/client/assets/{cypher-CayLeiaR.js → cypher-CGStaC1X.js} +0 -0
  255. package/dist/client/assets/{d-BMZQ0mAy.js → d-CuTCIvnX.js} +0 -0
  256. package/dist/client/assets/{dark-plus-B__q47Nr.js → dark-plus-BvePH-r3.js} +0 -0
  257. package/dist/client/assets/{dart-gMOEMyuz.js → dart-CqEodbm2.js} +0 -0
  258. package/dist/client/assets/{dax-C3t5LadU.js → dax-UdE5S0Dh.js} +0 -0
  259. package/dist/client/assets/{desktop-DmhXLwLR.js → desktop-DfmsfHJA.js} +0 -0
  260. package/dist/client/assets/{diff-togOXQX6.js → diff-CW0RWGd9.js} +0 -0
  261. package/dist/client/assets/{docker--6N01olR.js → docker-B1qtW4ha.js} +0 -0
  262. package/dist/client/assets/{dotenv-Bq930Yx8.js → dotenv-BUzOh1k8.js} +0 -0
  263. package/dist/client/assets/{dracula-CBkSghcw.js → dracula-kJQjC_Gy.js} +0 -0
  264. package/dist/client/assets/{dracula-soft-CCSYeoxL.js → dracula-soft-B3XhEjCl.js} +0 -0
  265. package/dist/client/assets/{dream-maker-BiMf3DHl.js → dream-maker-CBvk18nW.js} +0 -0
  266. package/dist/client/assets/{emacs-lisp-Dhht7he2.js → emacs-lisp-DvSgLhDc.js} +0 -0
  267. package/dist/client/assets/{everforest-dark-NqSz4oHS.js → everforest-dark-u0zLn75q.js} +0 -0
  268. package/dist/client/assets/{everforest-light-a3Yzs_lT.js → everforest-light-D3syIoAR.js} +0 -0
  269. package/dist/client/assets/{fennel-BExc9TZf.js → fennel-C-1kWlGf.js} +0 -0
  270. package/dist/client/assets/{fish-C2p-AJmZ.js → fish-CCpdtwqS.js} +0 -0
  271. package/dist/client/assets/{fluent-CeYzs8Qy.js → fluent-BLg032oD.js} +0 -0
  272. package/dist/client/assets/{fortran-free-form-BIQEK2Jw.js → fortran-free-form-Br4jRtSc.js} +0 -0
  273. package/dist/client/assets/{gdscript-B5JQPh_-.js → gdscript-hSAZM1eh.js} +0 -0
  274. package/dist/client/assets/{gdshader-vVjJ_Qr8.js → gdshader-D4XNAEs9.js} +0 -0
  275. package/dist/client/assets/{genie-DGl5rqC8.js → genie-DmN-ICAN.js} +0 -0
  276. package/dist/client/assets/{gherkin-CY_VLUnD.js → gherkin-cuHHmRcX.js} +0 -0
  277. package/dist/client/assets/{github-dark-ClO4AStc.js → github-dark-CEBLh0--.js} +0 -0
  278. package/dist/client/assets/{github-dark-default-CM0dPco8.js → github-dark-default-Dq0Z4Xai.js} +0 -0
  279. package/dist/client/assets/{github-dark-dimmed-Cb6xxpXY.js → github-dark-dimmed-D90YmS4w.js} +0 -0
  280. package/dist/client/assets/{github-dark-high-contrast-BpYtx2-M.js → github-dark-high-contrast-B6BWv1iC.js} +0 -0
  281. package/dist/client/assets/{github-light-default-BmnCWL6x.js → github-light-default-DsPWmj4v.js} +0 -0
  282. package/dist/client/assets/{github-light-high-contrast-rpagNF5O.js → github-light-high-contrast-C7aLb3kp.js} +0 -0
  283. package/dist/client/assets/{github-light-CeOVFgf_.js → github-light-lXSVSq5T.js} +0 -0
  284. package/dist/client/assets/{gleam-BarIG9kQ.js → gleam-D8VhqPDN.js} +0 -0
  285. package/dist/client/assets/{gn-DhYsTPYc.js → gn-BjGRlX27.js} +0 -0
  286. package/dist/client/assets/{gnuplot-CucLlTBc.js → gnuplot-BZCXuE4q.js} +0 -0
  287. package/dist/client/assets/{go-toi-uWvg.js → go-BJpWXZEs.js} +0 -0
  288. package/dist/client/assets/{groovy-Ds4dis_k.js → groovy-D9w3Dn-z.js} +0 -0
  289. package/dist/client/assets/{gruvbox-dark-hard-aPiW8pQh.js → gruvbox-dark-hard-_deksD0U.js} +0 -0
  290. package/dist/client/assets/{gruvbox-dark-medium-2HJCvzsS.js → gruvbox-dark-medium-CT31284j.js} +0 -0
  291. package/dist/client/assets/{gruvbox-dark-soft-Da97ODX9.js → gruvbox-dark-soft-BZuEUCbj.js} +0 -0
  292. package/dist/client/assets/{gruvbox-light-hard-BXlEipFe.js → gruvbox-light-hard-dxv4n_ZS.js} +0 -0
  293. package/dist/client/assets/{gruvbox-light-medium-Cun-GjGk.js → gruvbox-light-medium-BsW_fVfR.js} +0 -0
  294. package/dist/client/assets/{gruvbox-light-soft-Bd3qiiSw.js → gruvbox-light-soft-BiGy99gD.js} +0 -0
  295. package/dist/client/assets/{haskell-B_jvz5Po.js → haskell-DqDdKEgk.js} +0 -0
  296. package/dist/client/assets/{haxe-BRbuo5UO.js → haxe-DMg0jS3a.js} +0 -0
  297. package/dist/client/assets/{hcl-BzNUCtsK.js → hcl-SZIZUK_X.js} +0 -0
  298. package/dist/client/assets/{hjson-BxVo3sS2.js → hjson-DF1VspiE.js} +0 -0
  299. package/dist/client/assets/{hlsl-C8Wes1nf.js → hlsl-DPe9L0Dt.js} +0 -0
  300. package/dist/client/assets/{horizon-D54PjLAY.js → horizon-Ngud75Kn.js} +0 -0
  301. package/dist/client/assets/{horizon-bright-D9RccdIr.js → horizon-bright-Cnljd0XD.js} +0 -0
  302. package/dist/client/assets/{houston-CMu1N_4K.js → houston-BenZxlMr.js} +0 -0
  303. package/dist/client/assets/{hy-dMrJKKU_.js → hy-B0f-B1mH.js} +0 -0
  304. package/dist/client/assets/{imba-DG_oO8tg.js → imba-Bq3j1cW5.js} +0 -0
  305. package/dist/client/assets/{ini-geHw79Aj.js → ini-BayloP2U.js} +0 -0
  306. package/dist/client/assets/{json5-CDUsNqz6.js → json5-CRSfdIrY.js} +0 -0
  307. package/dist/client/assets/{jsonc-D48xcwyD.js → jsonc-y4g9DQPx.js} +0 -0
  308. package/dist/client/assets/{jsonl-cpIYDXEe.js → jsonl-D2paVn9r.js} +0 -0
  309. package/dist/client/assets/{jsonnet-Da1lhszN.js → jsonnet-CLH27mtz.js} +0 -0
  310. package/dist/client/assets/{jssm-B8BLrEGL.js → jssm-CPPYaqX-.js} +0 -0
  311. package/dist/client/assets/{kanagawa-dragon-2Sk8Rx83.js → kanagawa-dragon-Bt5mhLu1.js} +0 -0
  312. package/dist/client/assets/{kanagawa-lotus-CQVSWfJp.js → kanagawa-lotus-FGA3pRJk.js} +0 -0
  313. package/dist/client/assets/{kanagawa-wave-BKWNioLX.js → kanagawa-wave-DnLVZPAD.js} +0 -0
  314. package/dist/client/assets/{kdl-B-2tSRmp.js → kdl-D1BQjjnw.js} +0 -0
  315. package/dist/client/assets/{kotlin-DepsEzh3.js → kotlin-ndCaDnf0.js} +0 -0
  316. package/dist/client/assets/{kusto-BcCtXIb8.js → kusto-D-4nbkD3.js} +0 -0
  317. package/dist/client/assets/{laserwave-BUqkO46F.js → laserwave-D2qAZkaG.js} +0 -0
  318. package/dist/client/assets/{lean-CNO9ffpX.js → lean-YmtAsB0p.js} +0 -0
  319. package/dist/client/assets/{less-Dj0T9pWC.js → less-DyHub3ow.js} +0 -0
  320. package/dist/client/assets/{light-plus-C9Hnuc1T.js → light-plus-CP13QUvm.js} +0 -0
  321. package/dist/client/assets/{llvm-DbV9b66l.js → llvm-DCcqrY0D.js} +0 -0
  322. package/dist/client/assets/{log-BMblmPyH.js → log-DWAAMNbe.js} +0 -0
  323. package/dist/client/assets/{logo-B78qMxws.js → logo-ClQMGkNL.js} +0 -0
  324. package/dist/client/assets/{luau-BUd8xsdE.js → luau-CmcXFvLt.js} +0 -0
  325. package/dist/client/assets/{make-Ev-6cJrd.js → make-DcfJyUzm.js} +0 -0
  326. package/dist/client/assets/{markdown-CS4LI6sN.js → markdown-DXxotAxn.js} +0 -0
  327. package/dist/client/assets/{material-theme-5rA1zn0D.js → material-theme-JFoPTBSr.js} +0 -0
  328. package/dist/client/assets/{material-theme-darker-DGOEiL65.js → material-theme-darker-BHaqZ19v.js} +0 -0
  329. package/dist/client/assets/{material-theme-lighter-CULfFRX0.js → material-theme-lighter-CGnnS2bs.js} +0 -0
  330. package/dist/client/assets/{material-theme-ocean-LQZ9CleP.js → material-theme-ocean-Drhewjqf.js} +0 -0
  331. package/dist/client/assets/{material-theme-palenight-Di_f5oks.js → material-theme-palenight-DbUypmpb.js} +0 -0
  332. package/dist/client/assets/{matlab-C0qEtAx9.js → matlab-BlfbTznR.js} +0 -0
  333. package/dist/client/assets/{mdx-CzvnbLXb.js → mdx-H8fyPQd8.js} +0 -0
  334. package/dist/client/assets/{mermaid-BPquZaKt.js → mermaid-CWAV2dmV.js} +0 -0
  335. package/dist/client/assets/{min-dark-rkuIbtJV.js → min-dark-BEelvXUB.js} +0 -0
  336. package/dist/client/assets/{min-light-Dj_HOGsr.js → min-light-CTPBOACR.js} +0 -0
  337. package/dist/client/assets/{mipsasm-k5DQoS6j.js → mipsasm-BWYFAm2s.js} +0 -0
  338. package/dist/client/assets/{mojo-sTTDuNnR.js → mojo-DZcPJEIN.js} +0 -0
  339. package/dist/client/assets/{monokai-D5p-u2ij.js → monokai-DQlZXbkg.js} +0 -0
  340. package/dist/client/assets/{moonbit-j5ChFtBC.js → moonbit-6eslNlJL.js} +0 -0
  341. package/dist/client/assets/{move-Dj0Gmn6R.js → move-DxFc9-QU.js} +0 -0
  342. package/dist/client/assets/{narrat-DJgMz2oW.js → narrat-gv38dJOT.js} +0 -0
  343. package/dist/client/assets/{nextflow-groovy-eDLuZ_oi.js → nextflow-groovy-DV4H3hok.js} +0 -0
  344. package/dist/client/assets/{night-owl-CEdtPl3A.js → night-owl-BLcrYhaC.js} +0 -0
  345. package/dist/client/assets/{night-owl-light-GdSldewm.js → night-owl-light-BG-tBJOz.js} +0 -0
  346. package/dist/client/assets/{nix-CxIPS3pb.js → nix-NlOz3HGM.js} +0 -0
  347. package/dist/client/assets/{nord-3WFAz5H9.js → nord-Dm2F5_QB.js} +0 -0
  348. package/dist/client/assets/{nushell-GDfBmoBU.js → nushell-D86Z8aFF.js} +0 -0
  349. package/dist/client/assets/{objective-c-MFQ_MGUa.js → objective-c-iuJvUjCv.js} +0 -0
  350. package/dist/client/assets/{objective-cpp-Y83LcBE7.js → objective-cpp-C62JvfMT.js} +0 -0
  351. package/dist/client/assets/{ocaml-FxYfaJxu.js → ocaml-Rbryo9lg.js} +0 -0
  352. package/dist/client/assets/{odin-CprihY3z.js → odin-CfaOVNP_.js} +0 -0
  353. package/dist/client/assets/{one-dark-pro-BB6mpmmA.js → one-dark-pro-DC9SHdX0.js} +0 -0
  354. package/dist/client/assets/{one-light-BYLoxNtg.js → one-light-Doo39p0H.js} +0 -0
  355. package/dist/client/assets/{openscad-Bc1FbpOi.js → openscad-DCRhgheK.js} +0 -0
  356. package/dist/client/assets/{pascal-Bb4d8cUL.js → pascal-CTesTHtV.js} +0 -0
  357. package/dist/client/assets/{pierre-dark-cF19s-RM.js → pierre-dark-Gtc9M_gS.js} +0 -0
  358. package/dist/client/assets/{pierre-light-BdpX8OpD.js → pierre-light-EDxMHmhf.js} +0 -0
  359. package/dist/client/assets/{pkl-tM25Sq0w.js → pkl-BjUMjQkt.js} +0 -0
  360. package/dist/client/assets/{plastic-D3k2Xp_5.js → plastic-B3CcSpon.js} +0 -0
  361. package/dist/client/assets/{plsql-CLEfFhSj.js → plsql-BgKEZSSo.js} +0 -0
  362. package/dist/client/assets/{po-CaAzdrrh.js → po-C5s_CVt8.js} +0 -0
  363. package/dist/client/assets/{poimandres-bPTvT4Da.js → poimandres-BsK70ma5.js} +0 -0
  364. package/dist/client/assets/{polar-TG7aTGdK.js → polar-y4hX8qM0.js} +0 -0
  365. package/dist/client/assets/{postcss-8kqfa9f0.js → postcss-BHCm7Qae.js} +0 -0
  366. package/dist/client/assets/{powerquery-CtSu1Nfd.js → powerquery-C2vMt8aZ.js} +0 -0
  367. package/dist/client/assets/{powershell-87lLBHMy.js → powershell-DEcjmg1c.js} +0 -0
  368. package/dist/client/assets/{prisma-Dnf694DZ.js → prisma-Ba-Tcxy5.js} +0 -0
  369. package/dist/client/assets/{prolog-C0XbHTWa.js → prolog-B4o261Jv.js} +0 -0
  370. package/dist/client/assets/{proto-BZP-HLIb.js → proto-o3IZKiMR.js} +0 -0
  371. package/dist/client/assets/{puppet-CJYWgYC5.js → puppet-BC0dqZ31.js} +0 -0
  372. package/dist/client/assets/{purescript-B95Q6BAd.js → purescript-CLDw1y5G.js} +0 -0
  373. package/dist/client/assets/{python-CqTCsi7P.js → python-D1NFioGW.js} +0 -0
  374. package/dist/client/assets/{qmldir-DlIL4hls.js → qmldir-B7i9e9Vn.js} +0 -0
  375. package/dist/client/assets/{qss-BW72E0q_.js → qss-DIe6oKX8.js} +0 -0
  376. package/dist/client/assets/{racket-CCAimEsC.js → racket-CAOC_yyk.js} +0 -0
  377. package/dist/client/assets/{raku-mSuqElkM.js → raku-Ccua3vW6.js} +0 -0
  378. package/dist/client/assets/{red-C-DA4yBI.js → red-DtDH206x.js} +0 -0
  379. package/dist/client/assets/{reg-CGwMBJ2c.js → reg-CAYZT9kE.js} +0 -0
  380. package/dist/client/assets/{rel-JwrbYgX4.js → rel-cvB6F5nO.js} +0 -0
  381. package/dist/client/assets/{riscv-CoYyE75b.js → riscv-SYGtE4EN.js} +0 -0
  382. package/dist/client/assets/{ron-C5wrhnmJ.js → ron-CRt869SB.js} +0 -0
  383. package/dist/client/assets/{rose-pine-DlrMPYYd.js → rose-pine-CjBfSJ5b.js} +0 -0
  384. package/dist/client/assets/{rose-pine-dawn-DBHFtZD2.js → rose-pine-dawn-C0xwy7iJ.js} +0 -0
  385. package/dist/client/assets/{rose-pine-moon-BBfrpe5q.js → rose-pine-moon-BSNy9Ty0.js} +0 -0
  386. package/dist/client/assets/{rosmsg-DlimTR9t.js → rosmsg-BwrfJ66Z.js} +0 -0
  387. package/dist/client/assets/{rust-Cxnkxx3h.js → rust-DCKTTPxN.js} +0 -0
  388. package/dist/client/assets/{sass-DEyqUIpU.js → sass-CorcwySt.js} +0 -0
  389. package/dist/client/assets/{scala-i3RN3yAN.js → scala-DlI-OmYj.js} +0 -0
  390. package/dist/client/assets/{scheme-BcKdjYkO.js → scheme-CcNEGkZH.js} +0 -0
  391. package/dist/client/assets/{sdbl-Be_XWc3n.js → sdbl-AL_m-RO_.js} +0 -0
  392. package/dist/client/assets/{slack-dark-3PDtm74m.js → slack-dark-rMhrfPm6.js} +0 -0
  393. package/dist/client/assets/{slack-ochin-CwiuFRJD.js → slack-ochin-9w8X74hU.js} +0 -0
  394. package/dist/client/assets/{smalltalk-BdBlL6ks.js → smalltalk-Y2ogrfbk.js} +0 -0
  395. package/dist/client/assets/{snazzy-light-Dyqc8Is2.js → snazzy-light-DHr9ygpP.js} +0 -0
  396. package/dist/client/assets/{solarized-dark-DZiTscIX.js → solarized-dark-UPcKev9Q.js} +0 -0
  397. package/dist/client/assets/{solarized-light-DBcfxrfG.js → solarized-light-DUsjROvl.js} +0 -0
  398. package/dist/client/assets/{solidity-DH-yUSWc.js → solidity-Bfbm9QZQ.js} +0 -0
  399. package/dist/client/assets/{splunk-CIjc4kxs.js → splunk-6DJA2XFa.js} +0 -0
  400. package/dist/client/assets/{ssh-config-BKVd4drG.js → ssh-config-CbQtdF-u.js} +0 -0
  401. package/dist/client/assets/{stylus-tqAsmugv.js → stylus-B_iq45Sj.js} +0 -0
  402. package/dist/client/assets/{swift-CdDBQ3_Z.js → swift-C7KIgN-p.js} +0 -0
  403. package/dist/client/assets/{synthwave-84-CbbRs73K.js → synthwave-84-lf_Wt0K_.js} +0 -0
  404. package/dist/client/assets/{system-verilog-CBqEY-9v.js → system-verilog-C3G9wERd.js} +0 -0
  405. package/dist/client/assets/{systemd-khRP5zwK.js → systemd-CwxGrojj.js} +0 -0
  406. package/dist/client/assets/{talonscript-D_lneH-6.js → talonscript-DqnSo1EO.js} +0 -0
  407. package/dist/client/assets/{tasl-CLymawGe.js → tasl-T8ethp86.js} +0 -0
  408. package/dist/client/assets/{tcl-BRY1S87U.js → tcl-Ccl366o0.js} +0 -0
  409. package/dist/client/assets/{terraform-BqohMo2f.js → terraform-BBf6ZI_0.js} +0 -0
  410. package/dist/client/assets/{tokyo-night-BWUONxad.js → tokyo-night-BF5ata25.js} +0 -0
  411. package/dist/client/assets/{toml-C4c85Lwg.js → toml-C5Z_BR4r.js} +0 -0
  412. package/dist/client/assets/{tsv-DsZq9HBQ.js → tsv-rX8sUJs7.js} +0 -0
  413. package/dist/client/assets/{turtle-Dpr8zLlw.js → turtle-BM-MG8WY.js} +0 -0
  414. package/dist/client/assets/{typespec-DcqgATB-.js → typespec-C5gKydvR.js} +0 -0
  415. package/dist/client/assets/{typst-CeVxmuPg.js → typst--_5VchrY.js} +0 -0
  416. package/dist/client/assets/{v-C2Qsh2-1.js → v-C6PwpmTC.js} +0 -0
  417. package/dist/client/assets/{vala-CvZ3yL7c.js → vala-4pTaceSj.js} +0 -0
  418. package/dist/client/assets/{vb-B_p4qDw4.js → vb-DhoR5A6S.js} +0 -0
  419. package/dist/client/assets/{verilog-D8MGjxD7.js → verilog-B9f_1lPn.js} +0 -0
  420. package/dist/client/assets/{vesper-DossXiE1.js → vesper-CmBi_iCT.js} +0 -0
  421. package/dist/client/assets/{vhdl-MLyYh_Gz.js → vhdl-Cy4RAmOe.js} +0 -0
  422. package/dist/client/assets/{viml-BuYIArcz.js → viml-CFQW-CcD.js} +0 -0
  423. package/dist/client/assets/{vitesse-black-C3kc1227.js → vitesse-black-CE8RoBJP.js} +0 -0
  424. package/dist/client/assets/{vitesse-dark-kWOu5V36.js → vitesse-dark-BpF142p_.js} +0 -0
  425. package/dist/client/assets/{vitesse-light-DMtiL8bK.js → vitesse-light-CMwxPBrg.js} +0 -0
  426. package/dist/client/assets/{vyper-CNqG09-_.js → vyper-BW5zj9bE.js} +0 -0
  427. package/dist/client/assets/{wasm-BsQDV7Y0.js → wasm-BigxSLnm.js} +0 -0
  428. package/dist/client/assets/{wasm-DFVlQlgd.js → wasm-CSccDuAq.js} +0 -0
  429. package/dist/client/assets/{wenyan-BmOQge13.js → wenyan-BZzM1SQT.js} +0 -0
  430. package/dist/client/assets/{wgsl-CgWrmvIg.js → wgsl-xBPHbLlq.js} +0 -0
  431. package/dist/client/assets/{wikitext-DkwckXCk.js → wikitext-BXJWUNJK.js} +0 -0
  432. package/dist/client/assets/{wit-CtyVFGe7.js → wit-2GnUs67P.js} +0 -0
  433. package/dist/client/assets/{wolfram-CXE4FrKz.js → wolfram-DIFDmw-g.js} +0 -0
  434. package/dist/client/assets/{zenscript-DH15wJt0.js → zenscript-DQaUUjbx.js} +0 -0
  435. package/dist/client/assets/{zig-CqXN9brD.js → zig-BDepRvBi.js} +0 -0
  436. package/dist/{update-check-KL-2sGxE.mjs → update-check-DAPFCqpF.mjs} +1 -1
package/dist/cli.mjs CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { C as revertHunk, S as listRepoFiles, T as toSafeRelativePath, _ as getRepoRoot, a as extractPlanLines, b as gitAddFile, c as formatComments, d as getFileContent, f as getGitDiffAsync, g as getRepoName, h as getProjectStorageDir, i as writeServerLock, l as getBranchName, m as getMergeStatus, o as formatPlanReview, p as getHunkHistory, r as removeServerLock, s as sectionTitleForLine, u as getCustomGitDiffAsync, v as getTabSizeForFiles, w as isSafePath, x as isGitRepo, y as getUntrackedFilePathsAsync } from "./server-lock-DpCrvL-Z.mjs";
2
+ import { C as toSafeRelativePath, S as isSafePath, _ as getUntrackedFilePathsAsync, a as formatComments, b as listRepoFiles, c as getFileContent, d as getMergeStatus, f as getProjectStorageDir, g as getTabSizeForFiles, h as getShowDiff, i as writeServerLock, l as getGitDiffAsync, m as getRepoRoot, o as getBranchName, p as getRepoName, r as removeServerLock, s as getCustomGitDiffAsync, u as getHunkHistory, v as gitAddFile, x as revertHunk, y as isGitRepo } from "./server-lock-D73NKKbn.mjs";
3
+ import { n as formatPlanReview, r as sectionTitleForLine, t as extractPlanLines } from "./plan-format-mSDtsPcC.mjs";
4
+ import { execFile, execFileSync, spawn } from "node:child_process";
3
5
  import { fileURLToPath } from "node:url";
4
- import { dirname, extname, join, resolve } from "node:path";
6
+ import { dirname, extname, isAbsolute, join, resolve } from "node:path";
5
7
  import { existsSync, mkdirSync, readFileSync, watch, writeFileSync } from "node:fs";
6
8
  import getPort from "get-port";
7
- import { parseArgs } from "node:util";
8
- import { execFileSync } from "node:child_process";
9
+ import { parseArgs, promisify } from "node:util";
9
10
  import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
10
11
  import { homedir } from "node:os";
11
12
  import { Hono } from "hono";
@@ -48,7 +49,11 @@ const DEFAULTS$1 = {
48
49
  help: false,
49
50
  version: false,
50
51
  includeUnstaged: true,
51
- includeUntracked: true
52
+ includeUntracked: true,
53
+ tui: false,
54
+ gpu: false,
55
+ showMode: false,
56
+ showRevspecs: []
52
57
  };
53
58
  /**
54
59
  * All git-diff option definitions for `node:util.parseArgs`.
@@ -173,6 +178,15 @@ const DIFFING_OPTIONS = {
173
178
  type: "boolean",
174
179
  default: false
175
180
  },
181
+ tui: {
182
+ type: "boolean",
183
+ default: false
184
+ },
185
+ gpu: {
186
+ type: "boolean",
187
+ default: false
188
+ },
189
+ "gh-pr": { type: "string" },
176
190
  help: {
177
191
  type: "boolean",
178
192
  short: "h"
@@ -209,18 +223,37 @@ Output Modes:
209
223
  - Terminal mode: when output is a pipe, redirect, or non-TTY
210
224
  - Web mode: when output is a TTY (interactive terminal)
211
225
 
212
- Force a mode with --web or --terminal flags.
226
+ Force a mode with --web, --terminal, or --tui flags.
227
+ --tui is experimental and opt-in. It opens a native-Rust terminal
228
+ interface that mirrors the web dashboard. Falls back to git diff
229
+ output if the environment cannot support a TUI (piped stdin, CI,
230
+ missing binary).
231
+
232
+ Subcommands:
233
+ show <revspec>... Drop-in for 'git show'. Renders commit metadata
234
+ (subject, author, date, message body) above the
235
+ diff in the web UI. Accepts single commits,
236
+ ranges (a..b, a...b), tags, and multiple SHAs.
237
+ Use '--' to separate revspecs from pathspecs.
213
238
 
214
239
  Examples:
215
240
  diffing Review uncommitted changes (web UI)
216
241
  diffing --staged Review staged changes
217
242
  diffing HEAD~3 Review last 3 commits
218
243
  diffing main..feature Compare branches
244
+ diffing show HEAD Review a single commit's metadata + diff
245
+ diffing show HEAD~3..HEAD Review the last 3 commits as a series
246
+ diffing show HEAD -- src/ Limit a commit review to a directory
219
247
  diffing --diff-algorithm=patience src/ Diff with patience algorithm
220
248
  diffing -U10 Diff with 10 context lines
221
249
  diffing --word-diff=color Word-level diff in color
222
250
  diffing -b -w Ignore whitespace changes
223
- diffing --host 0.0.0.0 Allow other machines on the LAN to review`);
251
+ diffing --host 0.0.0.0 Allow other machines on the LAN to review
252
+ diffing --tui Open the experimental TUI (native Rust)
253
+
254
+ Note: 'diffing <sha>' runs 'git diff <sha>' (working tree vs <sha>); it
255
+ is not the same as 'diffing show <sha>'. Use 'show' when you want to
256
+ review a commit's changes.`);
224
257
  }
225
258
  function printGitDiffHelp() {
226
259
  console.log(`
@@ -464,7 +497,8 @@ function parseDiffOptions(rawArgs) {
464
497
  }
465
498
  for (let i = dashDashIdx + 1; i < rawArgs.length; i++) opts.pathspecs.push(rawArgs[i]);
466
499
  } else for (const p of positionals) opts.revisions.push(p);
467
- if (values.web) opts.outputMode = "web";
500
+ if (values.tui) opts.outputMode = "tui";
501
+ else if (values.web) opts.outputMode = "web";
468
502
  else if (values.terminal) opts.outputMode = "terminal";
469
503
  if (process.stdout.isTTY && opts.outputMode === "auto") opts.outputMode = "web";
470
504
  else if (!process.stdout.isTTY && opts.outputMode === "auto") opts.outputMode = "terminal";
@@ -545,6 +579,21 @@ function buildGitDiffArgs(opts) {
545
579
  }
546
580
  return args;
547
581
  }
582
+ /**
583
+ * Transform a `parseDiffOptions(...)` result into a "show mode" variant:
584
+ * moves any parsed revisions into `showRevspecs`, clears `revisions` (so the
585
+ * existing diff-engine path does not try to `git diff` them), and sets the
586
+ * `showMode` flag. Pathspecs and every other flag survive unchanged.
587
+ *
588
+ * Returns the same object for callsite ergonomics — the mutation is in-place
589
+ * because `parseDiffOptions` always returns a fresh object.
590
+ */
591
+ function intoShowMode(opts) {
592
+ opts.showRevspecs = opts.revisions;
593
+ opts.revisions = [];
594
+ opts.showMode = true;
595
+ return opts;
596
+ }
548
597
  //#endregion
549
598
  //#region src/lib/diff-engine.ts
550
599
  const MAX_BUFFER = 50 * 1024 * 1024;
@@ -553,10 +602,11 @@ const MAX_BUFFER = 50 * 1024 * 1024;
553
602
  * or a "custom" mode (specific revisions / pathspecs).
554
603
  *
555
604
  * Custom mode is used when the user provides explicit revisions or pathspecs
556
- * beyond just toggling staged/untracked.
605
+ * beyond just toggling staged/untracked. `showMode` is *also* a custom mode
606
+ * — the "Show staged / Show untracked" toggles don't apply to a commit view.
557
607
  */
558
608
  function isCustomMode$1(opts) {
559
- return opts.revisions.length > 0 || opts.pathspecs.length > 0;
609
+ return opts.revisions.length > 0 || opts.pathspecs.length > 0 || opts.showMode;
560
610
  }
561
611
  function parseFilePaths(patch) {
562
612
  const paths = /* @__PURE__ */ new Set();
@@ -603,8 +653,24 @@ function parseBinaryFiles(patch, untrackedFiles) {
603
653
  }
604
654
  /**
605
655
  * Execute a diff asynchronously — used by the server.
656
+ *
657
+ * Show mode bypasses the normal `git diff` path entirely: it resolves
658
+ * revspecs to a commit list and fetches per-commit metadata + patches in
659
+ * one `git log` call. The concatenated patch is returned in the same shape
660
+ * the existing UI pipeline expects (so file tree, binary detection, and
661
+ * tab-size detection all keep working unchanged); the per-commit data
662
+ * rides along on `commits` for the metadata banners.
606
663
  */
607
664
  async function executeDiffAsync(opts) {
665
+ if (opts.showMode) {
666
+ const { commits, patch, truncated } = await getShowDiff(opts.showRevspecs, opts.pathspecs);
667
+ return {
668
+ patch,
669
+ args: [],
670
+ commits,
671
+ truncated
672
+ };
673
+ }
608
674
  if (isCustomMode$1(opts)) {
609
675
  const args = buildGitDiffArgs(opts);
610
676
  return {
@@ -624,10 +690,10 @@ async function executeDiffAsync(opts) {
624
690
  * Execute a diff and produce the full enriched result used by the web API.
625
691
  */
626
692
  async function executeDiffWithMeta(opts) {
627
- const { patch } = await executeDiffAsync(opts);
693
+ const { patch, commits, truncated } = await executeDiffAsync(opts);
628
694
  const repoName = getRepoName();
629
695
  const branch = getBranchName();
630
- const untrackedFiles = opts.includeUntracked ? await getUntrackedFilePathsAsync() : [];
696
+ const untrackedFiles = opts.includeUntracked && !opts.showMode ? await getUntrackedFilePathsAsync() : [];
631
697
  const binaryFiles = parseBinaryFiles(patch, new Set(untrackedFiles));
632
698
  const filePaths = parseFilePaths(patch);
633
699
  return {
@@ -637,14 +703,19 @@ async function executeDiffWithMeta(opts) {
637
703
  tabSizeMap: getTabSizeForFiles(filePaths),
638
704
  untrackedFiles,
639
705
  repoName,
640
- branch
706
+ branch,
707
+ ...commits ? { commits } : {},
708
+ ...truncated ? { truncated } : {}
641
709
  };
642
710
  }
643
711
  /**
644
712
  * Run the diff in terminal mode: forward to git diff with full flags,
645
- * output to stdout. Behaves identically to `git diff`.
713
+ * output to stdout. Behaves identically to `git diff`. In show mode this
714
+ * delegates to `git show` instead so `diffing show <rev>... --terminal`
715
+ * is a drop-in for `git show <rev>...`.
646
716
  */
647
717
  function runTerminalDiff(opts) {
718
+ if (opts.showMode) return runTerminalShow(opts);
648
719
  const args = buildGitDiffArgs(opts);
649
720
  const enforceDefaults = !opts.outputFormat && !opts.quiet;
650
721
  const finalArgs = [];
@@ -665,6 +736,30 @@ function runTerminalDiff(opts) {
665
736
  }
666
737
  }
667
738
  /**
739
+ * Terminal mode for `diffing show`: spawn `git show` with the user's revspecs
740
+ * and pathspecs, inherit stdio, propagate exit code. We pass `--no-ext-diff`
741
+ * so the output is a clean unified diff regardless of the user's git config
742
+ * (matches the web-mode pipeline), but otherwise hand everything to git.
743
+ */
744
+ function runTerminalShow(opts) {
745
+ const args = [
746
+ "show",
747
+ "--no-ext-diff",
748
+ ...opts.showRevspecs
749
+ ];
750
+ if (opts.pathspecs.length > 0) args.push("--", ...opts.pathspecs);
751
+ try {
752
+ execFileSync("git", args, {
753
+ encoding: "utf-8",
754
+ maxBuffer: MAX_BUFFER,
755
+ stdio: "inherit"
756
+ });
757
+ return 0;
758
+ } catch (err) {
759
+ return err.status ?? 1;
760
+ }
761
+ }
762
+ /**
668
763
  * Validate the environment: check that we're in a git repo.
669
764
  * Returns an error message or null.
670
765
  */
@@ -1236,6 +1331,42 @@ var FileCommentStore = class {
1236
1331
  function newId() {
1237
1332
  return crypto.randomUUID();
1238
1333
  }
1334
+ /**
1335
+ * Backfill / repair a plan loaded from disk so it matches the current schema.
1336
+ * Older persisted plans may be missing `versions` and `createdAtPlanVersion`;
1337
+ * we synthesize sensible values so callers can always rely on the new fields.
1338
+ */
1339
+ function backfillPlan(plan) {
1340
+ const currentVersion = plan.version ?? 1;
1341
+ const have = Array.isArray(plan.versions) ? plan.versions.length : 0;
1342
+ if (!plan.versions || have === 0 || have < currentVersion) {
1343
+ const createdAt = plan.updatedAt ?? plan.createdAt ?? Date.now();
1344
+ const haveEntries = Array.isArray(plan.versions) ? plan.versions : [];
1345
+ const present = new Set(haveEntries.map((v) => v.version));
1346
+ const next = [];
1347
+ for (let i = 1; i <= currentVersion; i++) {
1348
+ const existing = haveEntries.find((v) => v.version === i);
1349
+ if (existing) next.push(existing);
1350
+ else next.push({
1351
+ version: i,
1352
+ body: plan.body,
1353
+ title: plan.title,
1354
+ source: plan.source,
1355
+ model: plan.model,
1356
+ createdAt
1357
+ });
1358
+ }
1359
+ plan.versions = next.filter((v) => v.version >= 1 && v.version <= currentVersion);
1360
+ if (have < currentVersion || !present.has(currentVersion)) markBackfilled(plan);
1361
+ }
1362
+ if (plan.comments) {
1363
+ for (const c of plan.comments) if (typeof c.createdAtPlanVersion !== "number") c.createdAtPlanVersion = plan.version ?? 1;
1364
+ }
1365
+ if (!plan.comments) plan.comments = [];
1366
+ }
1367
+ function markBackfilled(plan) {
1368
+ plan.__backfilledVersions = true;
1369
+ }
1239
1370
  /** Shared mutation helpers so both stores behave identically. */
1240
1371
  function applyUpsert(plans, input, now) {
1241
1372
  if (input.id) {
@@ -1247,6 +1378,15 @@ function applyUpsert(plans, input, now) {
1247
1378
  if (input.model !== void 0) existing.model = input.model;
1248
1379
  existing.version += 1;
1249
1380
  existing.updatedAt = now;
1381
+ if (!existing.versions) existing.versions = [];
1382
+ existing.versions.push({
1383
+ version: existing.version,
1384
+ body: existing.body,
1385
+ title: existing.title,
1386
+ source: existing.source,
1387
+ model: existing.model,
1388
+ createdAt: now
1389
+ });
1250
1390
  existing.decision = "pending";
1251
1391
  existing.decisionComment = void 0;
1252
1392
  existing.decidedAt = void 0;
@@ -1263,11 +1403,43 @@ function applyUpsert(plans, input, now) {
1263
1403
  updatedAt: now,
1264
1404
  version: 1,
1265
1405
  decision: "pending",
1266
- comments: []
1406
+ comments: [],
1407
+ versions: [{
1408
+ version: 1,
1409
+ body: input.body,
1410
+ title: input.title,
1411
+ source: input.source,
1412
+ model: input.model,
1413
+ createdAt: now
1414
+ }]
1267
1415
  };
1268
1416
  plans.push(plan);
1269
1417
  return plan;
1270
1418
  }
1419
+ /**
1420
+ * Keep the most-recent `PlanVersion` snapshot in sync with the current `Plan`
1421
+ * fields after a non-resubmit edit (PUT). Doesn't add a new entry — that only
1422
+ * happens via `upsert` (the resubmit flow).
1423
+ */
1424
+ function syncCurrentVersion(plan) {
1425
+ if (!plan.versions || plan.versions.length === 0) plan.versions = [];
1426
+ if (plan.versions.length === 0) {
1427
+ plan.versions.push({
1428
+ version: plan.version,
1429
+ body: plan.body,
1430
+ title: plan.title,
1431
+ source: plan.source,
1432
+ model: plan.model,
1433
+ createdAt: plan.updatedAt
1434
+ });
1435
+ return;
1436
+ }
1437
+ const last = plan.versions[plan.versions.length - 1];
1438
+ last.body = plan.body;
1439
+ last.title = plan.title;
1440
+ last.source = plan.source;
1441
+ last.model = plan.model;
1442
+ }
1271
1443
  var FilePlanStore = class {
1272
1444
  dirPath;
1273
1445
  filePath;
@@ -1285,7 +1457,19 @@ var FilePlanStore = class {
1285
1457
  async getAll() {
1286
1458
  try {
1287
1459
  const data = await readFile(this.filePath, "utf-8");
1288
- return JSON.parse(data);
1460
+ const plans = JSON.parse(data);
1461
+ let anyBackfilled = false;
1462
+ for (const p of plans) {
1463
+ const before = Array.isArray(p.versions) ? p.versions.length : 0;
1464
+ const beforeValid = Array.isArray(p.versions) && p.versions.length > 0;
1465
+ backfillPlan(p);
1466
+ const after = Array.isArray(p.versions) ? p.versions.length : 0;
1467
+ if ((!beforeValid || before < (p.version ?? 1)) && after > before) anyBackfilled = true;
1468
+ }
1469
+ if (anyBackfilled) try {
1470
+ await this.save(plans);
1471
+ } catch {}
1472
+ return plans;
1289
1473
  } catch {
1290
1474
  return [];
1291
1475
  }
@@ -1293,6 +1477,11 @@ var FilePlanStore = class {
1293
1477
  async get(id) {
1294
1478
  return (await this.getAll()).find((p) => p.id === id) ?? null;
1295
1479
  }
1480
+ async getVersion(id, version) {
1481
+ const plan = await this.get(id);
1482
+ if (!plan) return null;
1483
+ return plan.versions.find((v) => v.version === version) ?? null;
1484
+ }
1296
1485
  async save(plans) {
1297
1486
  try {
1298
1487
  await mkdir(this.dirPath, { recursive: true });
@@ -1300,7 +1489,12 @@ var FilePlanStore = class {
1300
1489
  const repoRoot = getRepoRoot();
1301
1490
  await writeFile(join(this.dirPath, "repo_path.txt"), repoRoot, "utf-8");
1302
1491
  } catch {}
1303
- await writeFile(this.filePath, JSON.stringify(plans, null, 2), "utf-8");
1492
+ const clean = plans.map((p) => {
1493
+ const copy = { ...p };
1494
+ delete copy.__backfilledVersions;
1495
+ return copy;
1496
+ });
1497
+ await writeFile(this.filePath, JSON.stringify(clean, null, 2), "utf-8");
1304
1498
  } catch (err) {
1305
1499
  console.error("Failed to save plans to file:", err);
1306
1500
  }
@@ -1308,6 +1502,7 @@ var FilePlanStore = class {
1308
1502
  async upsert(input) {
1309
1503
  const plans = await this.getAll();
1310
1504
  const plan = applyUpsert(plans, input, Date.now());
1505
+ backfillPlan(plan);
1311
1506
  await this.save(plans);
1312
1507
  return plan;
1313
1508
  }
@@ -1320,6 +1515,8 @@ var FilePlanStore = class {
1320
1515
  if (fields.source !== void 0) plan.source = fields.source;
1321
1516
  if (fields.model !== void 0) plan.model = fields.model;
1322
1517
  plan.updatedAt = Date.now();
1518
+ syncCurrentVersion(plan);
1519
+ backfillPlan(plan);
1323
1520
  await this.save(plans);
1324
1521
  return plan;
1325
1522
  }
@@ -1348,11 +1545,13 @@ var FilePlanStore = class {
1348
1545
  if (!plan) return null;
1349
1546
  if (!plan.comments) plan.comments = [];
1350
1547
  if (!fn(plan)) return null;
1548
+ backfillPlan(plan);
1351
1549
  await this.save(plans);
1352
1550
  return plan;
1353
1551
  }
1354
1552
  async addComment(planId, comment) {
1355
1553
  return this.mutate(planId, (plan) => {
1554
+ if (typeof comment.createdAtPlanVersion !== "number") comment.createdAtPlanVersion = plan.version ?? 1;
1356
1555
  plan.comments.push(comment);
1357
1556
  return true;
1358
1557
  });
@@ -1378,6 +1577,7 @@ var FilePlanStore = class {
1378
1577
  return this.mutate(planId, (plan) => {
1379
1578
  const c = plan.comments.find((x) => x.id === commentId);
1380
1579
  if (!c) return false;
1580
+ if (typeof c.createdAtPlanVersion === "number" && typeof reply.createdAtPlanVersion !== "number") reply.createdAtPlanVersion = c.createdAtPlanVersion;
1381
1581
  if (!c.replies) c.replies = [];
1382
1582
  c.replies.push(reply);
1383
1583
  return true;
@@ -1438,6 +1638,62 @@ var FileUiStateStore = class {
1438
1638
  }
1439
1639
  };
1440
1640
  //#endregion
1641
+ //#region src/lib/editor-launcher.ts
1642
+ function resolveEditorCommand(editor, absolutePath, platform = process.platform, env = process.env) {
1643
+ switch (editor) {
1644
+ case "vscode": return guiEditorCommand("code", absolutePath, platform);
1645
+ case "zed": return guiEditorCommand("zed", absolutePath, platform);
1646
+ case "vim": return terminalEditorCommand("vim", absolutePath, platform, env);
1647
+ case "neovim": return terminalEditorCommand("nvim", absolutePath, platform, env);
1648
+ default: return null;
1649
+ }
1650
+ }
1651
+ function guiEditorCommand(bin, absolutePath, platform) {
1652
+ if (platform === "win32") return {
1653
+ cmd: `${bin}.cmd`,
1654
+ args: [absolutePath]
1655
+ };
1656
+ return {
1657
+ cmd: bin,
1658
+ args: [absolutePath]
1659
+ };
1660
+ }
1661
+ function terminalEditorCommand(bin, absolutePath, platform, env) {
1662
+ if (platform === "darwin") return {
1663
+ cmd: "osascript",
1664
+ args: ["-e", `tell application "Terminal" to do script "${bin} \\"${absolutePath.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}\\""`]
1665
+ };
1666
+ if (platform === "win32") return {
1667
+ cmd: "cmd.exe",
1668
+ args: [
1669
+ "/c",
1670
+ "start",
1671
+ "\"\"",
1672
+ "cmd.exe",
1673
+ "/k",
1674
+ bin,
1675
+ absolutePath
1676
+ ]
1677
+ };
1678
+ const term = env.TERMINAL?.trim();
1679
+ if (term) return {
1680
+ cmd: term,
1681
+ args: [
1682
+ "-e",
1683
+ bin,
1684
+ absolutePath
1685
+ ]
1686
+ };
1687
+ return {
1688
+ cmd: "x-terminal-emulator",
1689
+ args: [
1690
+ "-e",
1691
+ bin,
1692
+ absolutePath
1693
+ ]
1694
+ };
1695
+ }
1696
+ //#endregion
1441
1697
  //#region src/lib/review-session.ts
1442
1698
  var ReviewSession = class {
1443
1699
  round = 0;
@@ -1502,7 +1758,8 @@ var ReviewSession = class {
1502
1758
  commentXml: input.commentXml,
1503
1759
  openCount: input.openCount,
1504
1760
  comments: input.comments,
1505
- decision: input.decision
1761
+ decision: input.decision,
1762
+ mode: input.mode ?? "standard"
1506
1763
  };
1507
1764
  this.lastPayload = payload;
1508
1765
  const waiters = [...this.waiters];
@@ -1596,7 +1853,8 @@ var PlanReviewSession = class {
1596
1853
  decisionComment: input.decisionComment,
1597
1854
  reviewXml: input.reviewXml,
1598
1855
  openCommentCount: input.openCommentCount,
1599
- plan: input.plan
1856
+ plan: input.plan,
1857
+ mode: input.mode ?? "standard"
1600
1858
  };
1601
1859
  this.lastPayload = payload;
1602
1860
  const waiters = [...this.waiters];
@@ -1630,6 +1888,483 @@ var PlanReviewSession = class {
1630
1888
  }
1631
1889
  };
1632
1890
  //#endregion
1891
+ //#region src/lib/pr-session.ts
1892
+ var FilePrSessionStore = class {
1893
+ dirPath;
1894
+ filePath;
1895
+ constructor(storageDir) {
1896
+ this.dirPath = storageDir ?? getProjectStorageDir();
1897
+ this.filePath = join(this.dirPath, "pr-session.json");
1898
+ }
1899
+ async get() {
1900
+ try {
1901
+ const data = await readFile(this.filePath, "utf-8");
1902
+ return JSON.parse(data);
1903
+ } catch {
1904
+ return null;
1905
+ }
1906
+ }
1907
+ async save(session) {
1908
+ try {
1909
+ await mkdir(this.dirPath, { recursive: true });
1910
+ await writeFile(this.filePath, JSON.stringify(session, null, 2), "utf-8");
1911
+ } catch (err) {
1912
+ console.error("Failed to save pr-session to file:", err);
1913
+ }
1914
+ }
1915
+ async set(session) {
1916
+ await this.save(session);
1917
+ }
1918
+ async update(fields) {
1919
+ const current = await this.get();
1920
+ if (!current) return null;
1921
+ const next = {
1922
+ ...current,
1923
+ ...fields
1924
+ };
1925
+ await this.save(next);
1926
+ return next;
1927
+ }
1928
+ async clear() {
1929
+ try {
1930
+ const { unlink } = await import("node:fs/promises");
1931
+ await unlink(this.filePath);
1932
+ } catch {}
1933
+ }
1934
+ };
1935
+ //#endregion
1936
+ //#region src/lib/github.ts
1937
+ const execFileAsync = promisify(execFile);
1938
+ /**
1939
+ * Probe the `gh` CLI: is it on `$PATH`, and is the user authenticated?
1940
+ * Never throws — returns a permissive `available: false` on any failure.
1941
+ */
1942
+ async function detectGhCli() {
1943
+ try {
1944
+ const { stdout } = await execFileAsync("gh", ["--version"], { encoding: "utf-8" });
1945
+ const version = stdout.split("\n")[0]?.trim() || void 0;
1946
+ try {
1947
+ const result = await execFileAsync("gh", ["auth", "status"], { encoding: "utf-8" });
1948
+ return {
1949
+ available: true,
1950
+ authenticated: true,
1951
+ version,
1952
+ user: parseGhAuthStatusUser(`${result.stdout ?? ""}\n${result.stderr ?? ""}`)
1953
+ };
1954
+ } catch {
1955
+ return {
1956
+ available: true,
1957
+ authenticated: false,
1958
+ version
1959
+ };
1960
+ }
1961
+ } catch {
1962
+ return {
1963
+ available: false,
1964
+ authenticated: false
1965
+ };
1966
+ }
1967
+ }
1968
+ /**
1969
+ * Extract the GitHub username from `gh auth status` output. Exported for
1970
+ * unit tests — see `__tests__/github-auth.test.ts`.
1971
+ *
1972
+ * Real-world samples:
1973
+ * `✓ Logged in to github.com account octocat (keyring)` (gh 2.40+)
1974
+ * `Logged in to github.com as octocat (oauth_token)` (older gh)
1975
+ * ` ✓ Logged in to github.com as octocat (~/.config/gh/hosts.yml)`
1976
+ */
1977
+ function parseGhAuthStatusUser(output) {
1978
+ const account = /Logged in to [^\s]+ account\s+([^\s(]+)/.exec(output);
1979
+ if (account) return account[1];
1980
+ return /Logged in to [^\s]+ as\s+([^\s(]+)/.exec(output)?.[1];
1981
+ }
1982
+ /** Read the most-preferred GitHub token from the env. */
1983
+ function readGithubToken() {
1984
+ const env = process.env;
1985
+ return env.GH_TOKEN || env.GITHUB_TOKEN || env.GITHUB_API_TOKEN || null;
1986
+ }
1987
+ function parsePrRef(input, cwdRepo) {
1988
+ const trimmed = input.trim();
1989
+ const urlMatch = /^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/i.exec(trimmed);
1990
+ if (urlMatch) return {
1991
+ owner: urlMatch[1],
1992
+ repo: urlMatch[2],
1993
+ pullNumber: Number(urlMatch[3]),
1994
+ ref: trimmed
1995
+ };
1996
+ const shorthand = /^([^/\s]+)\/([^#\s]+)#(\d+)$/.exec(trimmed);
1997
+ if (shorthand) return {
1998
+ owner: shorthand[1],
1999
+ repo: shorthand[2],
2000
+ pullNumber: Number(shorthand[3]),
2001
+ ref: trimmed
2002
+ };
2003
+ const bare = /^#?(\d+)$/.exec(trimmed);
2004
+ if (bare && cwdRepo) return {
2005
+ owner: cwdRepo.owner,
2006
+ repo: cwdRepo.repo,
2007
+ pullNumber: Number(bare[1]),
2008
+ ref: trimmed
2009
+ };
2010
+ if (bare) throw new Error(`Cannot resolve bare PR number "${trimmed}" — run from inside the target repo, or pass a full URL or \`owner/repo#1234\`.`);
2011
+ throw new Error(`Unrecognised PR ref: ${trimmed}`);
2012
+ }
2013
+ /**
2014
+ * Best-effort: derive `{ owner, repo }` for the current working directory
2015
+ * from `git remote get-url origin`. Falls back to throwing.
2016
+ */
2017
+ async function detectCwdRepo() {
2018
+ try {
2019
+ const { stdout } = await execFileAsync("git", [
2020
+ "remote",
2021
+ "get-url",
2022
+ "origin"
2023
+ ], { encoding: "utf-8" });
2024
+ const url = stdout.trim();
2025
+ const m = /github\.com[:/]([^/\s]+)\/([^/\s]+?)(?:\.git)?\s*$/.exec(url);
2026
+ if (m) return {
2027
+ owner: m[1],
2028
+ repo: m[2]
2029
+ };
2030
+ } catch {}
2031
+ return null;
2032
+ }
2033
+ /**
2034
+ * Fetch PR metadata + diff + existing review comments using `gh`.
2035
+ * Throws with a user-readable message on failure.
2036
+ */
2037
+ async function fetchPrMetadataViaGh(resolved) {
2038
+ const args = ["-R", `${resolved.owner}/${resolved.repo}`];
2039
+ let metaJson;
2040
+ try {
2041
+ const { stdout } = await execFileAsync("gh", [
2042
+ "pr",
2043
+ "view",
2044
+ String(resolved.pullNumber),
2045
+ ...args,
2046
+ "--json",
2047
+ "number,title,url,author,baseRefOid,headRefOid,additions,deletions,changedFiles,headRepositoryOwner,headRepository"
2048
+ ], {
2049
+ encoding: "utf-8",
2050
+ maxBuffer: 20 * 1024 * 1024
2051
+ });
2052
+ metaJson = JSON.parse(stdout);
2053
+ } catch (err) {
2054
+ const stderr = err?.stderr || err?.message || "unknown error";
2055
+ throw new Error(`gh pr view failed: ${stderr.trim()}`);
2056
+ }
2057
+ let diff = "";
2058
+ try {
2059
+ const { stdout } = await execFileAsync("gh", [
2060
+ "pr",
2061
+ "diff",
2062
+ String(resolved.pullNumber),
2063
+ ...args
2064
+ ], {
2065
+ encoding: "utf-8",
2066
+ maxBuffer: 50 * 1024 * 1024
2067
+ });
2068
+ diff = stdout;
2069
+ } catch (err) {
2070
+ const stderr = err?.stderr || err?.message || "unknown error";
2071
+ throw new Error(`gh pr diff failed: ${stderr.trim()}`);
2072
+ }
2073
+ const headOwner = metaJson.headRepositoryOwner?.login || metaJson.headRepository?.owner?.login || resolved.owner;
2074
+ const repoName = metaJson.headRepository?.name || resolved.repo;
2075
+ const author = metaJson.author ? {
2076
+ login: metaJson.author.login,
2077
+ avatarUrl: metaJson.author.avatarUrl
2078
+ } : null;
2079
+ const existingComments = await fetchExistingCommentsViaGh(resolved);
2080
+ return {
2081
+ number: metaJson.number,
2082
+ title: metaJson.title,
2083
+ url: metaJson.url,
2084
+ author,
2085
+ baseSha: metaJson.baseRefOid,
2086
+ headSha: metaJson.headRefOid,
2087
+ additions: metaJson.additions,
2088
+ deletions: metaJson.deletions,
2089
+ changedFiles: metaJson.changedFiles,
2090
+ owner: headOwner,
2091
+ repo: repoName,
2092
+ diff,
2093
+ existingComments
2094
+ };
2095
+ }
2096
+ async function fetchExistingCommentsViaGh(resolved) {
2097
+ `${resolved.owner}${resolved.repo}`;
2098
+ const endpoint = `repos/${resolved.owner}/${resolved.repo}/pulls/${resolved.pullNumber}/comments`;
2099
+ const reviewsEndpoint = `repos/${resolved.owner}/${resolved.repo}/pulls/${resolved.pullNumber}/reviews`;
2100
+ let reviews = [];
2101
+ try {
2102
+ const { stdout } = await execFileAsync("gh", [
2103
+ "api",
2104
+ reviewsEndpoint,
2105
+ "--paginate"
2106
+ ], {
2107
+ encoding: "utf-8",
2108
+ maxBuffer: 20 * 1024 * 1024
2109
+ });
2110
+ const all = JSON.parse(stdout);
2111
+ if (Array.isArray(all)) reviews = all;
2112
+ } catch {}
2113
+ reviews.sort((a, b) => a.submitted_at < b.submitted_at ? 1 : -1);
2114
+ const recentReviews = reviews.slice(0, 50);
2115
+ const reviewStateById = /* @__PURE__ */ new Map();
2116
+ for (const r of recentReviews) reviewStateById.set(r.id, r.state);
2117
+ let commentsRaw = [];
2118
+ try {
2119
+ const { stdout } = await execFileAsync("gh", [
2120
+ "api",
2121
+ `${endpoint}?per_page=100`,
2122
+ "--paginate"
2123
+ ], {
2124
+ encoding: "utf-8",
2125
+ maxBuffer: 20 * 1024 * 1024
2126
+ });
2127
+ const parsed = JSON.parse(stdout);
2128
+ if (Array.isArray(parsed)) commentsRaw = parsed;
2129
+ } catch {
2130
+ return [];
2131
+ }
2132
+ const byId = /* @__PURE__ */ new Map();
2133
+ for (const c of commentsRaw) byId.set(c.id, c);
2134
+ const replyByParent = /* @__PURE__ */ new Map();
2135
+ for (const c of commentsRaw) if (c.in_reply_to_id && byId.has(c.in_reply_to_id)) {
2136
+ const list = replyByParent.get(c.in_reply_to_id) ?? [];
2137
+ list.push(c);
2138
+ replyByParent.set(c.in_reply_to_id, list);
2139
+ }
2140
+ const tops = [];
2141
+ for (const c of commentsRaw) {
2142
+ if (c.in_reply_to_id) continue;
2143
+ const state = c.pull_request_review_id ? reviewStateById.get(c.pull_request_review_id) ?? null : null;
2144
+ tops.push({
2145
+ id: c.id,
2146
+ author: c.user ? {
2147
+ login: c.user.login,
2148
+ avatarUrl: c.user.avatar_url
2149
+ } : null,
2150
+ body: c.body ?? "",
2151
+ path: c.path,
2152
+ line: typeof c.line === "number" ? c.line : null,
2153
+ side: c.side === "LEFT" || c.side === "RIGHT" ? c.side : null,
2154
+ createdAt: c.created_at,
2155
+ updatedAt: c.updated_at,
2156
+ state,
2157
+ replies: (replyByParent.get(c.id) ?? []).map((r) => ({
2158
+ id: r.id,
2159
+ author: r.user ? {
2160
+ login: r.user.login,
2161
+ avatarUrl: r.user.avatar_url
2162
+ } : null,
2163
+ body: r.body ?? "",
2164
+ createdAt: r.created_at,
2165
+ updatedAt: r.updated_at
2166
+ })),
2167
+ isOutdated: typeof c.position === "number" && c.position === null ? false : false
2168
+ });
2169
+ }
2170
+ tops.sort((a, b) => {
2171
+ if (a.path !== b.path) return a.path.localeCompare(b.path);
2172
+ return (a.line ?? 0) - (b.line ?? 0);
2173
+ });
2174
+ return tops;
2175
+ }
2176
+ /**
2177
+ * POST the review to GitHub. Prefers `gh api` (uses the user's existing
2178
+ * `gh auth`); falls back to a direct HTTP call with `$GITHUB_TOKEN` when
2179
+ * `gh` is unavailable.
2180
+ */
2181
+ async function submitReview(input) {
2182
+ const gh = await detectGhCli();
2183
+ if (gh.available && gh.authenticated) return submitViaGh(input);
2184
+ const token = readGithubToken();
2185
+ if (token) return submitViaToken(input, token);
2186
+ return {
2187
+ ok: false,
2188
+ authSource: "none",
2189
+ error: "Cannot submit: no `gh` CLI on $PATH (or not authenticated) and no $GITHUB_TOKEN env var. Run `gh auth login` or set $GITHUB_TOKEN."
2190
+ };
2191
+ }
2192
+ /**
2193
+ * Map our `PrDecision` to the GitHub REST event string. Exported so the
2194
+ * test suite can pin the mapping (including the `rejected → REQUEST_CHANGES`
2195
+ * quirk, which exists because GitHub has no REJECT event).
2196
+ */
2197
+ function decisionToEvent(decision) {
2198
+ if (decision === "approve") return "APPROVE";
2199
+ if (decision === "request-changes") return "REQUEST_CHANGES";
2200
+ return "COMMENT";
2201
+ }
2202
+ /**
2203
+ * Expand multi-line `ReviewComment`s into N single-line `gh`-shaped entries
2204
+ * with `[part N/M]` prefixes. Exported for the test suite — the body of the
2205
+ * caller (`buildReviewPayload`) is otherwise private.
2206
+ *
2207
+ * Skips: non-`open` comments, file-level comments (`lineNumber === 0`).
2208
+ * Strips the `a/` / `b/` prefix from the file path (GitHub expects PR-relative
2209
+ * paths in the `path` field).
2210
+ */
2211
+ function expandMultiLineComments(comments) {
2212
+ const flat = [];
2213
+ for (const c of comments) {
2214
+ if (c.status !== "open") continue;
2215
+ if (c.lineNumber === 0) continue;
2216
+ const path = stripBPrefix(c.filePath);
2217
+ const start = c.startLineNumber && c.startLineNumber < c.lineNumber ? c.startLineNumber : c.lineNumber;
2218
+ const end = c.lineNumber;
2219
+ const span = end - start + 1;
2220
+ if (span > 1) for (let i = 0; i < span; i++) flat.push({
2221
+ path,
2222
+ line: start + i,
2223
+ side: "RIGHT",
2224
+ body: `[part ${i + 1}/${span}]\n${c.body}`
2225
+ });
2226
+ else flat.push({
2227
+ path,
2228
+ line: end,
2229
+ side: "RIGHT",
2230
+ body: c.body
2231
+ });
2232
+ }
2233
+ return flat;
2234
+ }
2235
+ function buildReviewPayload(input) {
2236
+ return {
2237
+ body: input.body,
2238
+ event: decisionToEvent(input.decision ?? "comment"),
2239
+ comments: expandMultiLineComments(input.comments ?? [])
2240
+ };
2241
+ }
2242
+ function stripBPrefix(path) {
2243
+ if (path.startsWith("b/")) return path.slice(2);
2244
+ if (path.startsWith("a/")) return path.slice(2);
2245
+ return path;
2246
+ }
2247
+ async function submitViaGh(input) {
2248
+ const payload = buildReviewPayload(input);
2249
+ `${input.resolved.owner}${input.resolved.repo}`;
2250
+ const args = [
2251
+ "api",
2252
+ "--method",
2253
+ "POST",
2254
+ `repos/${input.resolved.owner}/${input.resolved.repo}/pulls/${input.resolved.pullNumber}/reviews`,
2255
+ "-H",
2256
+ "Accept: application/vnd.github+json",
2257
+ "--input",
2258
+ "-"
2259
+ ];
2260
+ try {
2261
+ const { stdout } = await execFileAsync("gh", args, {
2262
+ encoding: "utf-8",
2263
+ maxBuffer: 20 * 1024 * 1024,
2264
+ input: JSON.stringify(payload)
2265
+ });
2266
+ const result = JSON.parse(stdout);
2267
+ return {
2268
+ ok: true,
2269
+ authSource: "gh",
2270
+ reviewId: result.id,
2271
+ reviewUrl: result.html_url
2272
+ };
2273
+ } catch (err) {
2274
+ const stdout = err?.stdout || "";
2275
+ const stderr = err?.stderr || err?.message || "unknown error";
2276
+ let parsed = null;
2277
+ try {
2278
+ parsed = JSON.parse(stdout);
2279
+ } catch {}
2280
+ return {
2281
+ ok: false,
2282
+ authSource: "gh",
2283
+ error: parsed?.message || stderr.trim()
2284
+ };
2285
+ }
2286
+ }
2287
+ async function submitViaToken(input, token) {
2288
+ const payload = buildReviewPayload(input);
2289
+ const url = `https://api.github.com/repos/${input.resolved.owner}/${input.resolved.repo}/pulls/${input.resolved.pullNumber}/reviews`;
2290
+ try {
2291
+ const res = await fetch(url, {
2292
+ method: "POST",
2293
+ headers: {
2294
+ Authorization: `Bearer ${token}`,
2295
+ Accept: "application/vnd.github+json",
2296
+ "X-GitHub-Api-Version": "2022-11-28",
2297
+ "Content-Type": "application/json",
2298
+ "User-Agent": "diffing-cli"
2299
+ },
2300
+ body: JSON.stringify(payload)
2301
+ });
2302
+ if (!res.ok) {
2303
+ const errBody = await res.text().catch(() => "");
2304
+ return {
2305
+ ok: false,
2306
+ authSource: "token",
2307
+ error: `HTTP ${res.status}: ${errBody.slice(0, 500)}`
2308
+ };
2309
+ }
2310
+ const result = await res.json();
2311
+ return {
2312
+ ok: true,
2313
+ authSource: "token",
2314
+ reviewId: result.id,
2315
+ reviewUrl: result.html_url
2316
+ };
2317
+ } catch (err) {
2318
+ return {
2319
+ ok: false,
2320
+ authSource: "token",
2321
+ error: err?.message || "Network error"
2322
+ };
2323
+ }
2324
+ }
2325
+ async function buildPrSession(ref) {
2326
+ const meta = await fetchPrMetadataViaGh(parsePrRef(ref, await detectCwdRepo() ?? void 0));
2327
+ return {
2328
+ ref,
2329
+ owner: meta.owner,
2330
+ repo: meta.repo,
2331
+ pullNumber: meta.number,
2332
+ baseSha: meta.baseSha,
2333
+ headSha: meta.headSha,
2334
+ title: meta.title,
2335
+ url: meta.url,
2336
+ author: meta.author,
2337
+ additions: meta.additions,
2338
+ deletions: meta.deletions,
2339
+ changedFiles: meta.changedFiles,
2340
+ diff: meta.diff,
2341
+ comments: [],
2342
+ existingComments: meta.existingComments
2343
+ };
2344
+ }
2345
+ /** Refresh `diff` + `existingComments` + head SHA in an existing session. */
2346
+ async function refreshPrSession(session) {
2347
+ const meta = await fetchPrMetadataViaGh({
2348
+ owner: session.owner,
2349
+ repo: session.repo,
2350
+ pullNumber: session.pullNumber,
2351
+ ref: session.ref
2352
+ });
2353
+ return {
2354
+ ...session,
2355
+ baseSha: meta.baseSha,
2356
+ headSha: meta.headSha,
2357
+ title: meta.title,
2358
+ url: meta.url,
2359
+ author: meta.author,
2360
+ additions: meta.additions,
2361
+ deletions: meta.deletions,
2362
+ changedFiles: meta.changedFiles,
2363
+ diff: meta.diff,
2364
+ existingComments: meta.existingComments
2365
+ };
2366
+ }
2367
+ //#endregion
1633
2368
  //#region src/server.ts
1634
2369
  const MIME_TYPES = {
1635
2370
  ".html": "text/html",
@@ -1647,13 +2382,14 @@ const MIME_TYPES = {
1647
2382
  ".avif": "image/avif"
1648
2383
  };
1649
2384
  function isCustomMode(opts) {
1650
- return opts.revisions.length > 0 || opts.pathspecs.length > 0;
2385
+ return opts.revisions.length > 0 || opts.pathspecs.length > 0 || opts.showMode;
1651
2386
  }
1652
- function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
2387
+ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore, prSessionStore) {
1653
2388
  const app = new Hono();
1654
2389
  const customMode = isCustomMode(diffOpts);
1655
2390
  const store = commentStore ?? new FileCommentStore();
1656
2391
  const plans = planStore ?? new FilePlanStore();
2392
+ const prStore = prSessionStore ?? new FilePrSessionStore();
1657
2393
  const uiStateStore = new FileUiStateStore();
1658
2394
  const viewedFiles = /* @__PURE__ */ new Set();
1659
2395
  const activeClients = /* @__PURE__ */ new Set();
@@ -1675,6 +2411,7 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
1675
2411
  mkdirSync(storageDir, { recursive: true });
1676
2412
  let commentsDebounce = null;
1677
2413
  let plansDebounce = null;
2414
+ let prSessionDebounce = null;
1678
2415
  watch(storageDir, (_eventType, filename) => {
1679
2416
  if (!filename) return;
1680
2417
  if (filename.startsWith("comments.json")) {
@@ -1683,6 +2420,9 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
1683
2420
  } else if (filename.startsWith("plans.json")) {
1684
2421
  if (plansDebounce) clearTimeout(plansDebounce);
1685
2422
  plansDebounce = setTimeout(() => broadcast("plans", Date.now().toString()), 120);
2423
+ } else if (filename.startsWith("pr-session.json")) {
2424
+ if (prSessionDebounce) clearTimeout(prSessionDebounce);
2425
+ prSessionDebounce = setTimeout(() => broadcast("pr-session", Date.now().toString()), 120);
1686
2426
  }
1687
2427
  }).unref();
1688
2428
  } catch (err) {
@@ -1743,11 +2483,40 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
1743
2483
  app.get("/api/diff", async (c) => {
1744
2484
  const staged = c.req.query("staged") === "true";
1745
2485
  const untracked = c.req.query("untracked") === "true";
1746
- const result = await executeDiffWithMeta(customMode ? diffOpts : {
2486
+ const prSession = await prStore.get();
2487
+ if (prSession) {
2488
+ const binaryFiles = [];
2489
+ const filePaths = [];
2490
+ for (const line of prSession.diff.split("\n")) {
2491
+ const m = /^diff --git a\/.+ b\/(.+)$/.exec(line);
2492
+ if (m) filePaths.push(m[1]);
2493
+ }
2494
+ return c.json({
2495
+ patch: prSession.diff,
2496
+ repoName: prSession.repo,
2497
+ branch: `#${prSession.pullNumber}`,
2498
+ customMode: true,
2499
+ binaryFiles,
2500
+ tabSizeMap: {},
2501
+ untrackedFiles: [],
2502
+ prMode: true,
2503
+ prRef: prSession.ref,
2504
+ prOwner: prSession.owner,
2505
+ prRepo: prSession.repo,
2506
+ prPullNumber: prSession.pullNumber,
2507
+ prUrl: prSession.url,
2508
+ prTitle: prSession.title,
2509
+ prAuthor: prSession.author,
2510
+ prHeadSha: prSession.headSha,
2511
+ prBaseSha: prSession.baseSha
2512
+ });
2513
+ }
2514
+ const optsForDiff = customMode ? diffOpts : {
1747
2515
  ...diffOpts,
1748
2516
  staged,
1749
2517
  includeUntracked: untracked
1750
- });
2518
+ };
2519
+ const result = await executeDiffWithMeta(optsForDiff);
1751
2520
  return c.json({
1752
2521
  patch: result.patch,
1753
2522
  repoName: result.repoName,
@@ -1755,7 +2524,10 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
1755
2524
  customMode,
1756
2525
  binaryFiles: result.binaryFiles,
1757
2526
  tabSizeMap: result.tabSizeMap,
1758
- untrackedFiles: result.untrackedFiles
2527
+ untrackedFiles: result.untrackedFiles,
2528
+ showMode: optsForDiff.showMode || void 0,
2529
+ commits: result.commits,
2530
+ truncated: result.truncated
1759
2531
  });
1760
2532
  });
1761
2533
  app.get("/api/file-content", (c) => {
@@ -1791,12 +2563,17 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
1791
2563
  const relPath = toSafeRelativePath(filePath, root);
1792
2564
  if (!relPath) return c.json({ error: "Forbidden file path" }, 403);
1793
2565
  const absolutePath = resolve(root, relPath);
1794
- const { exec } = await import("node:child_process");
1795
- if (editor === "vscode") exec(`code "${absolutePath}"`);
1796
- else if (editor === "zed") exec(`zed "${absolutePath}"`);
1797
- else if (editor === "vim") exec(`osascript -e 'tell application "Terminal" to do script "vim \\"${absolutePath}\\""'`);
1798
- else if (editor === "neovim") exec(`osascript -e 'tell application "Terminal" to do script "nvim \\"${absolutePath}\\""'`);
1799
- else await (await import("open")).default(absolutePath);
2566
+ if (editor && editor !== "default") {
2567
+ const command = resolveEditorCommand(editor, absolutePath);
2568
+ if (command) {
2569
+ const { execFile } = await import("node:child_process");
2570
+ execFile(command.cmd, command.args, (err) => {
2571
+ if (err) console.error(`Failed to launch ${editor} for ${absolutePath}: ${err.message}`);
2572
+ });
2573
+ return c.json({ ok: true });
2574
+ }
2575
+ }
2576
+ await (await import("open")).default(absolutePath);
1800
2577
  return c.json({ ok: true });
1801
2578
  } catch (err) {
1802
2579
  return c.json({ error: `Failed to open file: ${err.message}` }, 500);
@@ -1881,7 +2658,7 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
1881
2658
  try {
1882
2659
  const relPath = toSafeRelativePath(filePath, getRepoRoot());
1883
2660
  if (!relPath) return c.json({ error: "Forbidden file path" }, 403);
1884
- const history = getHunkHistory(relPath, deletionStart, deletionCount, diffOpts.revisions[0] || "HEAD");
2661
+ const history = getHunkHistory(relPath, deletionStart, deletionCount, diffOpts.showMode ? diffOpts.showRevspecs[diffOpts.showRevspecs.length - 1] || "HEAD" : diffOpts.revisions[0] || "HEAD");
1885
2662
  return c.json(history);
1886
2663
  } catch (err) {
1887
2664
  return c.json({ error: err.message || "Failed to fetch hunk history" }, 500);
@@ -2027,24 +2804,214 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
2027
2804
  if (!await store.remove(id)) return c.json({ error: "Comment not found" }, 404);
2028
2805
  return c.json({ ok: true });
2029
2806
  });
2807
+ /** Shared helper: 404 with a stable shape so the client knows "not in PR mode". */
2808
+ const notInPrMode = (c) => c.json({
2809
+ error: "Not in PR review mode",
2810
+ prMode: false
2811
+ }, 404);
2812
+ app.get("/api/gh/session", async (c) => {
2813
+ const session = await prStore.get();
2814
+ if (!session) return notInPrMode(c);
2815
+ return c.json({
2816
+ prMode: true,
2817
+ ref: session.ref,
2818
+ owner: session.owner,
2819
+ repo: session.repo,
2820
+ pullNumber: session.pullNumber,
2821
+ baseSha: session.baseSha,
2822
+ headSha: session.headSha,
2823
+ title: session.title,
2824
+ url: session.url,
2825
+ author: session.author,
2826
+ additions: session.additions,
2827
+ deletions: session.deletions,
2828
+ changedFiles: session.changedFiles,
2829
+ existingComments: session.existingComments,
2830
+ submittedAt: session.submittedAt,
2831
+ submittedReviewId: session.submittedReviewId,
2832
+ submittedReviewUrl: session.submittedReviewUrl,
2833
+ authSource: session.authSource
2834
+ });
2835
+ });
2836
+ /** Re-fetch PR metadata (head SHA, diff, existing comments) and persist. */
2837
+ app.post("/api/gh/pr/refresh", async (c) => {
2838
+ const session = await prStore.get();
2839
+ if (!session) return notInPrMode(c);
2840
+ try {
2841
+ const refreshed = await refreshPrSession(session);
2842
+ await prStore.set(refreshed);
2843
+ return c.json({
2844
+ ok: true,
2845
+ headSha: refreshed.headSha
2846
+ });
2847
+ } catch (err) {
2848
+ return c.json({ error: err?.message ?? "Refresh failed" }, 500);
2849
+ }
2850
+ });
2851
+ /** Initialize a PR session from a ref like `1234`, `o/r#42`, or a GitHub URL. */
2852
+ app.post("/api/gh/pr/init", async (c) => {
2853
+ const body = await c.req.json().catch(() => ({}));
2854
+ const ref = typeof body?.ref === "string" ? body.ref : "";
2855
+ if (!ref.trim()) return c.json({ error: "ref is required" }, 400);
2856
+ try {
2857
+ parsePrRef(ref, await detectCwdRepo() ?? void 0);
2858
+ const session = await buildPrSession(ref);
2859
+ await prStore.set(session);
2860
+ return c.json({
2861
+ ok: true,
2862
+ ref: session.ref,
2863
+ owner: session.owner,
2864
+ repo: session.repo,
2865
+ pullNumber: session.pullNumber,
2866
+ url: session.url
2867
+ });
2868
+ } catch (err) {
2869
+ return c.json({ error: err?.message ?? "Failed to initialise PR session" }, 500);
2870
+ }
2871
+ });
2872
+ app.get("/api/gh/pr-session/comments", async (c) => {
2873
+ const session = await prStore.get();
2874
+ if (!session) return notInPrMode(c);
2875
+ return c.json(session.comments ?? []);
2876
+ });
2877
+ app.post("/api/gh/pr-session/comments", async (c) => {
2878
+ const body = await c.req.json();
2879
+ const session = await prStore.get();
2880
+ if (!session) return notInPrMode(c);
2881
+ const comment = {
2882
+ id: crypto.randomUUID(),
2883
+ filePath: body.filePath,
2884
+ side: body.side,
2885
+ lineNumber: body.lineNumber,
2886
+ startLineNumber: body.startLineNumber,
2887
+ lineContent: body.lineContent,
2888
+ body: body.body,
2889
+ status: "open",
2890
+ createdAt: Date.now(),
2891
+ replies: []
2892
+ };
2893
+ const next = {
2894
+ ...session,
2895
+ comments: [...session.comments ?? [], comment]
2896
+ };
2897
+ await prStore.set(next);
2898
+ return c.json(comment, 201);
2899
+ });
2900
+ app.put("/api/gh/pr-session/comments/:id", async (c) => {
2901
+ const id = c.req.param("id");
2902
+ const { body, status } = await c.req.json();
2903
+ const session = await prStore.get();
2904
+ if (!session) return notInPrMode(c);
2905
+ const comments = (session.comments ?? []).map((cm) => cm.id === id ? {
2906
+ ...cm,
2907
+ body: body ?? cm.body,
2908
+ status: status ?? cm.status
2909
+ } : cm);
2910
+ await prStore.set({
2911
+ ...session,
2912
+ comments
2913
+ });
2914
+ const updated = comments.find((cm) => cm.id === id) ?? null;
2915
+ if (!updated) return c.json({ error: "Comment not found" }, 404);
2916
+ return c.json(updated);
2917
+ });
2918
+ app.delete("/api/gh/pr-session/comments/:id", async (c) => {
2919
+ const id = c.req.param("id");
2920
+ const session = await prStore.get();
2921
+ if (!session) return notInPrMode(c);
2922
+ const comments = (session.comments ?? []).filter((cm) => cm.id !== id);
2923
+ await prStore.set({
2924
+ ...session,
2925
+ comments
2926
+ });
2927
+ return c.json({ ok: true });
2928
+ });
2929
+ app.post("/api/gh/pr-session/comments/:id/replies", async (c) => {
2930
+ const id = c.req.param("id");
2931
+ const { body, role, model } = await c.req.json();
2932
+ const session = await prStore.get();
2933
+ if (!session) return notInPrMode(c);
2934
+ const comments = (session.comments ?? []).map((cm) => {
2935
+ if (cm.id !== id) return cm;
2936
+ const reply = {
2937
+ id: crypto.randomUUID(),
2938
+ body,
2939
+ createdAt: Date.now(),
2940
+ role: role || (model ? "agent" : "user"),
2941
+ model: model || void 0
2942
+ };
2943
+ return {
2944
+ ...cm,
2945
+ replies: [...cm.replies ?? [], reply]
2946
+ };
2947
+ });
2948
+ await prStore.set({
2949
+ ...session,
2950
+ comments
2951
+ });
2952
+ return c.json(comments.find((cm) => cm.id === id));
2953
+ });
2954
+ /** Submit the current PR session's review (new comments + verdict + body) to GitHub. */
2955
+ app.post("/api/gh/submit", async (c) => {
2956
+ const session = await prStore.get();
2957
+ if (!session) return notInPrMode(c);
2958
+ const body = await c.req.json().catch(() => ({}));
2959
+ const decision = body.decision;
2960
+ if (decision !== "approve" && decision !== "comment" && decision !== "request-changes") return c.json({ error: "decision must be one of: approve, comment, request-changes" }, 400);
2961
+ const generalBody = typeof body.body === "string" ? body.body : "";
2962
+ const dryRun = body.dryRun === true;
2963
+ const result = await submitReview({
2964
+ resolved: {
2965
+ owner: session.owner,
2966
+ repo: session.repo,
2967
+ pullNumber: session.pullNumber,
2968
+ ref: session.ref
2969
+ },
2970
+ decision,
2971
+ body: generalBody,
2972
+ comments: session.comments ?? []
2973
+ });
2974
+ if (result.ok && !dryRun) {
2975
+ const next = {
2976
+ ...session,
2977
+ submittedAt: Date.now(),
2978
+ submittedReviewId: result.reviewId,
2979
+ submittedReviewUrl: result.reviewUrl,
2980
+ authSource: result.authSource
2981
+ };
2982
+ await prStore.set(next);
2983
+ }
2984
+ return c.json({
2985
+ ok: result.ok,
2986
+ reviewId: result.reviewId,
2987
+ reviewUrl: result.reviewUrl,
2988
+ failedComments: result.failedComments ?? 0,
2989
+ authSource: result.authSource,
2990
+ error: result.error,
2991
+ dryRun
2992
+ });
2993
+ });
2030
2994
  app.post("/api/review/send", async (c) => {
2031
2995
  const body = await c.req.json().catch(() => ({}));
2032
2996
  const generalComment = typeof body?.generalComment === "string" ? body.generalComment : void 0;
2033
- const decision = body?.decision === "approved" || body?.decision === "changes-requested" || body?.decision === "rejected" ? body.decision : void 0;
2997
+ const decision = body?.decision === "approved" || body?.decision === "changes-requested" || body?.decision === "rejected" || body?.decision === "comment-only" ? body.decision : void 0;
2998
+ const mode = body?.mode === "comment-only" || body?.mode === "standard" ? body.mode : "standard";
2034
2999
  const all = await store.getAll();
2035
3000
  const openCount = all.filter((x) => x.status === "open").length;
2036
3001
  const payload = reviewSession.send({
2037
3002
  sentAt: Date.now(),
2038
- commentXml: formatComments(all, generalComment, decision),
3003
+ commentXml: formatComments(all, generalComment, decision, mode),
2039
3004
  openCount,
2040
3005
  comments: all,
2041
- decision
3006
+ decision,
3007
+ mode
2042
3008
  });
2043
3009
  return c.json({
2044
3010
  ok: true,
2045
3011
  round: payload.round,
2046
3012
  openCount: payload.openCount,
2047
3013
  decision: payload.decision,
3014
+ mode: payload.mode,
2048
3015
  waiters: reviewSession.snapshot().waiters
2049
3016
  });
2050
3017
  });
@@ -2071,6 +3038,29 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
2071
3038
  if (!plan) return c.json({ error: "Plan not found" }, 404);
2072
3039
  return c.json(plan);
2073
3040
  });
3041
+ app.get("/api/plans/:id/versions", async (c) => {
3042
+ const plan = await plans.get(c.req.param("id"));
3043
+ if (!plan) return c.json({ error: "Plan not found" }, 404);
3044
+ return c.json(plan.versions ?? []);
3045
+ });
3046
+ app.get("/api/plans/:id/versions/:n", async (c) => {
3047
+ const id = c.req.param("id");
3048
+ const n = Number(c.req.param("n"));
3049
+ if (!Number.isFinite(n) || n < 1) return c.json({ error: "version must be a positive integer" }, 400);
3050
+ const plan = await plans.get(id);
3051
+ if (!plan) return c.json({ error: "Plan not found" }, 404);
3052
+ const version = (plan.versions ?? []).find((v) => v.version === n);
3053
+ if (!version) return c.json({ error: `Version ${n} not found` }, 404);
3054
+ return c.json({
3055
+ version,
3056
+ plan: {
3057
+ id: plan.id,
3058
+ title: plan.title,
3059
+ decision: plan.decision,
3060
+ currentVersion: plan.version
3061
+ }
3062
+ });
3063
+ });
2074
3064
  app.post("/api/plans", async (c) => {
2075
3065
  const body = await c.req.json().catch(() => ({}));
2076
3066
  if (typeof body.body !== "string" || !body.body.trim()) return c.json({ error: "A plan body (markdown) is required" }, 400);
@@ -2110,6 +3100,7 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
2110
3100
  const anchorStart = startLineNumber ?? lineNumber;
2111
3101
  const lineContent = typeof body.lineContent === "string" && body.lineContent ? body.lineContent : lineNumber > 0 ? extractPlanLines(plan.body, anchorStart, lineNumber) : "";
2112
3102
  const sectionTitle = typeof body.sectionTitle === "string" && body.sectionTitle ? body.sectionTitle : lineNumber > 0 ? sectionTitleForLine(plan.body, anchorStart) : void 0;
3103
+ const createdAtPlanVersion = Number.isFinite(body.createdAtPlanVersion) ? Number(body.createdAtPlanVersion) : plan.version;
2113
3104
  const comment = {
2114
3105
  id: crypto.randomUUID(),
2115
3106
  lineNumber,
@@ -2119,6 +3110,7 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
2119
3110
  body: body.body,
2120
3111
  status: "open",
2121
3112
  createdAt: Date.now(),
3113
+ createdAtPlanVersion,
2122
3114
  replies: []
2123
3115
  };
2124
3116
  const updated = await plans.addComment(planId, comment);
@@ -2168,8 +3160,9 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
2168
3160
  const planId = c.req.param("id");
2169
3161
  const body = await c.req.json().catch(() => ({}));
2170
3162
  const decision = body.decision;
2171
- if (decision !== "approved" && decision !== "rejected" && decision !== "changes-requested") return c.json({ error: "decision must be one of: approved, rejected, changes-requested" }, 400);
3163
+ if (decision !== "approved" && decision !== "rejected" && decision !== "changes-requested" && decision !== "comment-only") return c.json({ error: "decision must be one of: approved, rejected, changes-requested, comment-only" }, 400);
2172
3164
  const decisionComment = typeof body.decisionComment === "string" ? body.decisionComment : void 0;
3165
+ const mode = body?.mode === "comment-only" || body?.mode === "standard" ? body.mode : "standard";
2173
3166
  const plan = await plans.setDecision(planId, decision, decisionComment);
2174
3167
  if (!plan) return c.json({ error: "Plan not found" }, 404);
2175
3168
  const openCommentCount = (plan.comments ?? []).filter((x) => x.status === "open").length;
@@ -2178,14 +3171,16 @@ function createApp(clientDir, diffOpts = DEFAULTS$1, commentStore, planStore) {
2178
3171
  planId,
2179
3172
  decision,
2180
3173
  decisionComment: plan.decisionComment,
2181
- reviewXml: formatPlanReview(plan),
3174
+ reviewXml: formatPlanReview(plan, { mode }),
2182
3175
  openCommentCount,
2183
- plan
3176
+ plan,
3177
+ mode
2184
3178
  });
2185
3179
  return c.json({
2186
3180
  ok: true,
2187
3181
  round: payload.round,
2188
3182
  decision,
3183
+ mode: payload.mode,
2189
3184
  openCommentCount,
2190
3185
  waiters: planReviewSession.snapshot().waiters
2191
3186
  });
@@ -2269,7 +3264,11 @@ async function newestActivityMs(projectDir) {
2269
3264
  return null;
2270
3265
  }
2271
3266
  };
2272
- for (const name of ["comments.json", "plans.json"]) {
3267
+ for (const name of [
3268
+ "comments.json",
3269
+ "plans.json",
3270
+ "pr-session.json"
3271
+ ]) {
2273
3272
  const file = join(projectDir, name);
2274
3273
  if (!existsSync(file)) continue;
2275
3274
  const m = await safeStat(file);
@@ -2320,14 +3319,35 @@ function startServer(options) {
2320
3319
  cleanupStaleProjects().catch((err) => {
2321
3320
  console.error("Failed to clean up stale projects:", err);
2322
3321
  });
3322
+ let prMode = false;
3323
+ const prReady = (async () => {
3324
+ if (!options.prRef) return;
3325
+ console.error(`Building PR session for ${options.prRef}...`);
3326
+ try {
3327
+ const store = new FilePrSessionStore();
3328
+ const existing = await store.get();
3329
+ if (!existing || existing.ref !== options.prRef) {
3330
+ const session = await buildPrSession(options.prRef);
3331
+ await store.set(session);
3332
+ }
3333
+ prMode = true;
3334
+ } catch (err) {
3335
+ console.error(`[pr-session] failed to build session for ${options.prRef}: ${err?.message ?? err}`);
3336
+ }
3337
+ })();
2323
3338
  const app = createApp(options.clientDir, options.diffOpts);
2324
3339
  return new Promise((resolve) => {
2325
- serve({
2326
- fetch: app.fetch,
2327
- port: options.port,
2328
- hostname: options.host
2329
- }, (info) => {
2330
- resolve({ port: info.port });
3340
+ prReady.then(() => {
3341
+ serve({
3342
+ fetch: app.fetch,
3343
+ port: options.port,
3344
+ hostname: options.host
3345
+ }, (info) => {
3346
+ resolve({
3347
+ port: info.port,
3348
+ prMode
3349
+ });
3350
+ });
2331
3351
  });
2332
3352
  });
2333
3353
  }
@@ -2464,7 +3484,7 @@ const QUOTES = [
2464
3484
  author: "Unknown"
2465
3485
  },
2466
3486
  {
2467
- text: "A QA engineer walks into a bar. Orders 0 beers. Orders 999999 beers. Orders NULL beers. Walks in through the window.",
3487
+ text: "A QA engineer walks into a coffie shop. Orders 0 cups. Orders 999999 cups. Orders NULL cups. Walks in through the window.",
2468
3488
  author: "Unknown"
2469
3489
  },
2470
3490
  {
@@ -2715,8 +3735,68 @@ function playStartupDisplay() {
2715
3735
  })();
2716
3736
  }
2717
3737
  //#endregion
3738
+ //#region src/lib/find-tui-binary.ts
3739
+ /**
3740
+ * Locate the `diffing-tui` native binary. Looks, in order:
3741
+ * 1. Sibling of the calling module (`dist/diffing-tui[.exe]` after build).
3742
+ * 2. `bin/diffing-tui[.exe]` next to the package root.
3743
+ * 3. `target/release/diffing-tui[.exe]` next to the package root
3744
+ * (cargo release build).
3745
+ * 4. `target/debug/diffing-tui[.exe]` next to the package root
3746
+ * (cargo debug build — the common case during development, especially
3747
+ * on Windows where release builds are slow).
3748
+ * 5. `$PATH` lookup via `which` / `where`.
3749
+ *
3750
+ * Returns the absolute path of the first match, or `null` if none are found.
3751
+ *
3752
+ * `callerUrl` is the `import.meta.url` of the caller — pass `import.meta.url`
3753
+ * from `cli.ts`. Exposed as a parameter so unit tests can pin the search
3754
+ * root to a known location instead of depending on the test runner's CWD.
3755
+ */
3756
+ function findTuiBinary$1(callerUrl) {
3757
+ const ext = process.platform === "win32" ? ".exe" : "";
3758
+ const here = dirname(fileURLToPath(callerUrl));
3759
+ const candidates = [
3760
+ resolve(here, `diffing-tui${ext}`),
3761
+ resolve(here, "..", "bin", `diffing-tui${ext}`),
3762
+ resolve(here, "..", "target", "release", `diffing-tui${ext}`),
3763
+ resolve(here, "..", "..", "target", "release", `diffing-tui${ext}`),
3764
+ resolve(here, "..", "target", "debug", `diffing-tui${ext}`),
3765
+ resolve(here, "..", "..", "target", "debug", `diffing-tui${ext}`)
3766
+ ];
3767
+ for (const c of candidates) if (existsSync(c)) return c;
3768
+ try {
3769
+ const out = execFileSync(process.platform === "win32" ? "where" : "which", ["diffing-tui"], {
3770
+ encoding: "utf-8",
3771
+ stdio: [
3772
+ "ignore",
3773
+ "pipe",
3774
+ "ignore"
3775
+ ]
3776
+ }).trim();
3777
+ if (out) {
3778
+ const first = out.split(/\r?\n/)[0]?.trim();
3779
+ if (first && isAbsolute(first)) return first;
3780
+ }
3781
+ } catch {}
3782
+ return null;
3783
+ }
3784
+ //#endregion
2718
3785
  //#region src/cli.ts
2719
3786
  const args = process.argv.slice(2);
3787
+ let prRef = null;
3788
+ let ghPrConsumed = 0;
3789
+ if (args[0]?.startsWith("gh pr ") === true) {
3790
+ const rest = args[0].slice(6).trim();
3791
+ if (rest) {
3792
+ prRef = rest;
3793
+ ghPrConsumed = 1;
3794
+ }
3795
+ } else if (args[0] === "gh" && args[1] === "pr" && args[2] !== void 0) {
3796
+ prRef = args[2];
3797
+ ghPrConsumed = 3;
3798
+ }
3799
+ if (ghPrConsumed > 0) args.splice(0, ghPrConsumed);
2720
3800
  if (new Set([
2721
3801
  "await-review",
2722
3802
  "reply",
@@ -2725,17 +3805,30 @@ if (new Set([
2725
3805
  "url",
2726
3806
  "mcp",
2727
3807
  "plan",
2728
- "update"
3808
+ "update",
3809
+ "gh"
2729
3810
  ]).has(args[0])) {
2730
3811
  if (args[0] === "mcp") {
2731
- const { startMcpServer } = await import("./mcp-CFeE13n-.mjs");
3812
+ const { startMcpServer } = await import("./mcp-DNZQvKKF.mjs");
2732
3813
  await startMcpServer();
2733
3814
  await new Promise(() => {});
2734
3815
  }
2735
- const { runSubcommand } = await import("./cli-agent-BNwY5lZE.mjs");
3816
+ const { runSubcommand } = await import("./cli-agent-B4hU6Xay.mjs");
2736
3817
  process.exit(await runSubcommand(args[0], args.slice(1)));
2737
3818
  }
3819
+ let showSubcommand = false;
3820
+ if (args[0] === "show") {
3821
+ showSubcommand = true;
3822
+ args.shift();
3823
+ }
2738
3824
  const opts = parseDiffOptions(args);
3825
+ if (showSubcommand) {
3826
+ if (opts.revisions.length === 0 && !opts.help && !opts.version) {
3827
+ console.error("Usage: diffing show <revspec>... [-- <pathspec>...]");
3828
+ process.exit(5);
3829
+ }
3830
+ intoShowMode(opts);
3831
+ }
2739
3832
  if (opts.help) {
2740
3833
  printHelp();
2741
3834
  process.exit(0);
@@ -2751,6 +3844,10 @@ if (envErr) {
2751
3844
  console.error(envErr);
2752
3845
  process.exit(1);
2753
3846
  }
3847
+ if (opts.outputMode === "tui") {
3848
+ const tuiResult = await launchTui(args);
3849
+ process.exit(tuiResult);
3850
+ }
2754
3851
  if (opts.outputMode === "terminal") {
2755
3852
  const exitCode = runTerminalDiff(opts);
2756
3853
  process.exit(exitCode);
@@ -2759,7 +3856,7 @@ const __pkgDir = dirname(fileURLToPath(import.meta.url));
2759
3856
  const currentVersion = JSON.parse(readFileSync(resolve(__pkgDir, "..", "package.json"), "utf-8")).version;
2760
3857
  const updateCheckPromise = (async () => {
2761
3858
  try {
2762
- const { checkForUpdates } = await import("./update-check-KL-2sGxE.mjs");
3859
+ const { checkForUpdates } = await import("./update-check-DAPFCqpF.mjs");
2763
3860
  return await checkForUpdates(currentVersion);
2764
3861
  } catch {
2765
3862
  return null;
@@ -2768,12 +3865,12 @@ const updateCheckPromise = (async () => {
2768
3865
  const port = await getPort(opts.port ? { port: opts.port } : void 0);
2769
3866
  const host = opts.host;
2770
3867
  const clientDir = resolve(__pkgDir, "client");
2771
- const { existsSync: existsSync$1 } = await import("node:fs");
2772
- const { port: actualPort } = await startServer({
3868
+ const { port: actualPort, prMode } = await startServer({
2773
3869
  port,
2774
3870
  host,
2775
- clientDir: existsSync$1(clientDir) ? clientDir : resolve(process.cwd(), "dist/client"),
2776
- diffOpts: opts
3871
+ clientDir: existsSync(clientDir) ? clientDir : resolve(process.cwd(), "dist/client"),
3872
+ diffOpts: opts,
3873
+ prRef: prRef ?? void 0
2777
3874
  });
2778
3875
  const localUrl = `http://${host}:${actualPort}`;
2779
3876
  try {
@@ -2789,7 +3886,9 @@ try {
2789
3886
  pid: process.pid,
2790
3887
  repoRoot,
2791
3888
  startedAt: Date.now(),
2792
- version: currentVersion
3889
+ version: currentVersion,
3890
+ mode: prMode ? "gh-pr" : "web",
3891
+ prRef: prMode ? prRef ?? void 0 : void 0
2793
3892
  });
2794
3893
  } catch {}
2795
3894
  console.log(`diffing server running at ${localUrl}`);
@@ -2797,7 +3896,7 @@ await playStartupDisplay();
2797
3896
  try {
2798
3897
  const updateInfo = await updateCheckPromise;
2799
3898
  if (updateInfo?.hasUpdate) {
2800
- const { printUpdateDisclaimer } = await import("./update-check-KL-2sGxE.mjs");
3899
+ const { printUpdateDisclaimer } = await import("./update-check-DAPFCqpF.mjs");
2801
3900
  printUpdateDisclaimer(currentVersion, updateInfo.latestVersion);
2802
3901
  }
2803
3902
  } catch {}
@@ -2817,5 +3916,64 @@ const shutdown = () => {
2817
3916
  };
2818
3917
  process.on("SIGINT", shutdown);
2819
3918
  process.on("SIGTERM", shutdown);
3919
+ /**
3920
+ * Wrapper around `findTuiBinary` that passes this script's `import.meta.url`
3921
+ * so the search paths anchor to the bundled CLI's directory. The real
3922
+ * implementation lives in `lib/find-tui-binary.ts` and is unit-tested there.
3923
+ */
3924
+ function findTuiBinary() {
3925
+ return findTuiBinary$1(import.meta.url);
3926
+ }
3927
+ /**
3928
+ * Fall back to default `git diff` output when the TUI cannot run.
3929
+ * Re-parses `args` so the terminal output exactly matches `diffing` (no flag)
3930
+ * in a non-TTY context.
3931
+ */
3932
+ function runTerminalFallback(args) {
3933
+ const terminalOpts = parseDiffOptions(args.filter((a) => a !== "--tui"));
3934
+ terminalOpts.outputMode = "terminal";
3935
+ terminalOpts.tui = false;
3936
+ return runTerminalDiff(terminalOpts);
3937
+ }
3938
+ /**
3939
+ * Launch the native-Rust TUI binary as a child process. Returns the process
3940
+ * exit code. If the TUI cannot start (no TTY, missing binary), prints a
3941
+ * single stderr line and falls back to the default `git diff` output.
3942
+ */
3943
+ async function launchTui(args) {
3944
+ if (!process.stdout.isTTY || !process.stdin.isTTY) {
3945
+ console.error("diffing --tui requires a TTY; falling back to git diff");
3946
+ return runTerminalFallback(args);
3947
+ }
3948
+ const bin = findTuiBinary();
3949
+ if (!bin) {
3950
+ console.error("diffing-tui binary not found; build it with `pnpm build:tui`; falling back to git diff");
3951
+ return runTerminalFallback(args);
3952
+ }
3953
+ const forwarded = args.filter((a) => a !== "--tui");
3954
+ let repoRoot;
3955
+ try {
3956
+ repoRoot = getRepoRoot();
3957
+ } catch {
3958
+ repoRoot = process.cwd();
3959
+ }
3960
+ console.log(`diffing TUI starting (binary: ${bin})`);
3961
+ await playStartupDisplay();
3962
+ return new Promise((resolveP) => {
3963
+ const child = spawn(bin, [
3964
+ "--repo",
3965
+ repoRoot,
3966
+ ...forwarded
3967
+ ], {
3968
+ stdio: "inherit",
3969
+ env: process.env
3970
+ });
3971
+ child.on("exit", (code) => resolveP(code ?? 0));
3972
+ child.on("error", (err) => {
3973
+ console.error(`diffing-tui failed to start: ${err.message}; falling back to git diff`);
3974
+ resolveP(runTerminalFallback(args));
3975
+ });
3976
+ });
3977
+ }
2820
3978
  //#endregion
2821
- export {};
3979
+ export { findTuiBinary };