diffing 0.11.0 → 0.12.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 (173) hide show
  1. package/README.md +2 -12
  2. package/dist/{cli-agent-DkwGxuy2.mjs → cli-agent-CWsOHN-j.mjs} +165 -53
  3. package/dist/{cli-gh-D0NfKpOp.mjs → cli-gh-DI69gJGo.mjs} +24 -14
  4. package/dist/cli.mjs +53 -22
  5. package/dist/client/assets/{angular-html-Dl53kkiy.js → angular-html-PLPuQo0k.js} +1 -1
  6. package/dist/client/assets/{angular-ts-wNJFFkey.js → angular-ts-CE02Ij4b.js} +1 -1
  7. package/dist/client/assets/{apl-BxtQST-h.js → apl-CsuUKZoi.js} +1 -1
  8. package/dist/client/assets/{arc-CBmZuzPB.js → arc-CgL5kFe-.js} +1 -1
  9. package/dist/client/assets/{architectureDiagram-3BPJPVTR-CEci_K9f.js → architectureDiagram-3BPJPVTR-DxZQWGnx.js} +1 -1
  10. package/dist/client/assets/{astro-BpADD5rh.js → astro-DkFc7sbz.js} +1 -1
  11. package/dist/client/assets/{blade-B4I5SQmP.js → blade-BkY07kcC.js} +1 -1
  12. package/dist/client/assets/{blockDiagram-GPEHLZMM-DcKhDtnE.js → blockDiagram-GPEHLZMM-D5a2KZV2.js} +1 -1
  13. package/dist/client/assets/{c-C3VtOgg8.js → c-T1BrPfJ6.js} +1 -1
  14. package/dist/client/assets/{c4Diagram-AAUBKEIU-CaHozoxF.js → c4Diagram-AAUBKEIU-mpMH4kFC.js} +1 -1
  15. package/dist/client/assets/channel-D3niKhl0.js +1 -0
  16. package/dist/client/assets/{chunk-2J33WTMH-tvuzKhdK.js → chunk-2J33WTMH-vMtgRLFH.js} +1 -1
  17. package/dist/client/assets/{chunk-3OPIFGDE-D_nBoD9w.js → chunk-3OPIFGDE-Dx-FqyO2.js} +1 -1
  18. package/dist/client/assets/{chunk-4BX2VUAB-yHPdy1G8.js → chunk-4BX2VUAB-CUrPd8Kv.js} +1 -1
  19. package/dist/client/assets/{chunk-55IACEB6-yXpL8wjV.js → chunk-55IACEB6-DHg3Nr8A.js} +1 -1
  20. package/dist/client/assets/{chunk-5ZQYHXKU-DZ5cvCDV.js → chunk-5ZQYHXKU-CpDPvbGs.js} +1 -1
  21. package/dist/client/assets/{chunk-727SXJPM-CJjgOWmY.js → chunk-727SXJPM-3VOGMxwk.js} +1 -1
  22. package/dist/client/assets/{chunk-AQP2D5EJ-CQYQKXSE.js → chunk-AQP2D5EJ-4dbfbIS6.js} +1 -1
  23. package/dist/client/assets/{chunk-BSJP7CBP-CP_f908b.js → chunk-BSJP7CBP-Dfyn0Uwp.js} +1 -1
  24. package/dist/client/assets/{chunk-CSCIHK7Q-tcgA8jR0.js → chunk-CSCIHK7Q-VTpSKo0F.js} +1 -1
  25. package/dist/client/assets/{chunk-FMBD7UC4-DlpmhBYg.js → chunk-FMBD7UC4-kXD1MyOL.js} +1 -1
  26. package/dist/client/assets/{chunk-KSCS5N6A-BkfieXpV.js → chunk-KSCS5N6A-BrVoWOAb.js} +1 -1
  27. package/dist/client/assets/{chunk-L5ZTLDWV-BjVXSZnt.js → chunk-L5ZTLDWV-wZEQDPsa.js} +1 -1
  28. package/dist/client/assets/{chunk-LZXEDZCA-CaAWmy4Q.js → chunk-LZXEDZCA-D3i0B0eg.js} +2 -2
  29. package/dist/client/assets/{chunk-ND2GUHAM-kWh41zUn.js → chunk-ND2GUHAM-hDVHT0bN.js} +1 -1
  30. package/dist/client/assets/{chunk-NZK2D7GU-CDrIi44_.js → chunk-NZK2D7GU-jQUfhp9h.js} +1 -1
  31. package/dist/client/assets/{chunk-O5CBEL6O-CbNGK3Te.js → chunk-O5CBEL6O-CX_vPWhk.js} +1 -1
  32. package/dist/client/assets/chunk-QZHKN3VN-CZLFuGpt.js +1 -0
  33. package/dist/client/assets/chunk-WU5MYG2G-BhcpjkaB.js +1 -0
  34. package/dist/client/assets/{chunk-XPW4576I-Cca0fTtG.js → chunk-XPW4576I-Co_-vDB4.js} +1 -1
  35. package/dist/client/assets/classDiagram-4FO5ZUOK-DK5KJNIt.js +1 -0
  36. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-y5K9t6Se.js +1 -0
  37. package/dist/client/assets/{cobol-j-6eG2UQ.js → cobol-8-qBLs-a.js} +1 -1
  38. package/dist/client/assets/{coffee-CZLH0dtt.js → coffee-Bjz5lkyW.js} +1 -1
  39. package/dist/client/assets/{cose-bilkent-S5V4N54A-DlxESVex.js → cose-bilkent-S5V4N54A-BljJ0FSA.js} +1 -1
  40. package/dist/client/assets/{cpp-j6Bp24RI.js → cpp-5BVQCBXT.js} +1 -1
  41. package/dist/client/assets/{crystal-DW7wcFUs.js → crystal-CCkY93GS.js} +1 -1
  42. package/dist/client/assets/{css-C43BDU2i.js → css-BTM7Tp2a.js} +1 -1
  43. package/dist/client/assets/{dagre-BM42HDAG-BaemEJFh.js → dagre-BM42HDAG-BSynd_2D.js} +1 -1
  44. package/dist/client/assets/{diagram-2AECGRRQ-BaM-bkJ3.js → diagram-2AECGRRQ-K3E2CVdy.js} +1 -1
  45. package/dist/client/assets/{diagram-5GNKFQAL-BOH04DJO.js → diagram-5GNKFQAL-BQHIrfKc.js} +1 -1
  46. package/dist/client/assets/{diagram-KO2AKTUF-BP5MyqDZ.js → diagram-KO2AKTUF-Bqs8sNN4.js} +1 -1
  47. package/dist/client/assets/{diagram-LMA3HP47-Dt4gKMYF.js → diagram-LMA3HP47-C9K4bpQe.js} +1 -1
  48. package/dist/client/assets/{diagram-OG6HWLK6-DoT1VshN.js → diagram-OG6HWLK6-DK6wIXY2.js} +1 -1
  49. package/dist/client/assets/{dist-DEAxvC4F.js → dist-1nkZYMRy.js} +1 -1
  50. package/dist/client/assets/{edge-D9ySFlnD.js → edge-DqN2FJce.js} +1 -1
  51. package/dist/client/assets/{elixir-CoJz_LQ5.js → elixir-BiAgRUFF.js} +1 -1
  52. package/dist/client/assets/{elm-CvedWh_e.js → elm-N1IbY8sz.js} +1 -1
  53. package/dist/client/assets/{erDiagram-TEJ5UH35-CMP78FsQ.js → erDiagram-TEJ5UH35-jsHCiP02.js} +1 -1
  54. package/dist/client/assets/{erb-lD_yYZsm.js → erb-B-yYlWAZ.js} +1 -1
  55. package/dist/client/assets/{flowDiagram-I6XJVG4X-Dp0s5BFj.js → flowDiagram-I6XJVG4X-DOB1dAWG.js} +1 -1
  56. package/dist/client/assets/{ganttDiagram-6RSMTGT7-GmSG31U-.js → ganttDiagram-6RSMTGT7-BYIewcY5.js} +1 -1
  57. package/dist/client/assets/{git-rebase-DwZABzof.js → git-rebase-CVkPxOAF.js} +1 -1
  58. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-C1SXShag.js → gitGraphDiagram-PVQCEYII-VNQzbpv2.js} +1 -1
  59. package/dist/client/assets/{glimmer-js-CWcs3w1Z.js → glimmer-js-BmG1xm72.js} +1 -1
  60. package/dist/client/assets/{glimmer-ts-CrzGN4lJ.js → glimmer-ts-CvTgwZsg.js} +1 -1
  61. package/dist/client/assets/{glsl-DRCtwX7h.js → glsl-DwjNNCbW.js} +1 -1
  62. package/dist/client/assets/{graphql-rpmrismS.js → graphql-BvgkyF8E.js} +1 -1
  63. package/dist/client/assets/{hack-Ba02RnuQ.js → hack-DH3188x2.js} +1 -1
  64. package/dist/client/assets/{haml-BHBACStm.js → haml-B0GTfMhX.js} +1 -1
  65. package/dist/client/assets/{handlebars-BtlQ1SCa.js → handlebars-he7hLDd9.js} +1 -1
  66. package/dist/client/assets/{html-BkVU3Dge.js → html-DIYgdTBq.js} +1 -1
  67. package/dist/client/assets/{html-derivative-DoK92vwi.js → html-derivative-2s6MXlci.js} +1 -1
  68. package/dist/client/assets/{http-CJAwKSPH.js → http-COS23XJP.js} +1 -1
  69. package/dist/client/assets/{hurl-kaX5jwuN.js → hurl-BlZPjeJt.js} +1 -1
  70. package/dist/client/assets/{index-BHeNiC07.js → index-BrEVVQOB.js} +154 -154
  71. package/dist/client/assets/{index-D8hOoJCg.css → index-BsuX6HVI.css} +1 -1
  72. package/dist/client/assets/{infoDiagram-5YYISTIA-B0i3BlNR.js → infoDiagram-5YYISTIA-DQRqk24I.js} +1 -1
  73. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-BN8sEei4.js → ishikawaDiagram-YF4QCWOH-DU1rqrLx.js} +1 -1
  74. package/dist/client/assets/{java-BvrigIoq.js → java-BAa5w-Qd.js} +1 -1
  75. package/dist/client/assets/{javascript-DZkPTYAi.js → javascript-C9e02ssI.js} +1 -1
  76. package/dist/client/assets/{jinja-Ceg7ui1S.js → jinja-Bx37xXwq.js} +1 -1
  77. package/dist/client/assets/{jison-iE1GaOyN.js → jison-m_DEf8Jo.js} +1 -1
  78. package/dist/client/assets/{journeyDiagram-JHISSGLW-CE6O3NhU.js → journeyDiagram-JHISSGLW-CoHlfevf.js} +1 -1
  79. package/dist/client/assets/{json-C0j8rEcg.js → json-DtN5AWRW.js} +1 -1
  80. package/dist/client/assets/{jsx-B7eXljgz.js → jsx-BlPpu8bR.js} +1 -1
  81. package/dist/client/assets/{julia-DMDw0aMP.js → julia-BAOmCbHl.js} +1 -1
  82. package/dist/client/assets/{just-BryMKRJ_.js → just-C_bvVjwE.js} +1 -1
  83. package/dist/client/assets/{kanban-definition-UN3LZRKU-j-aU6Yzp.js → kanban-definition-UN3LZRKU-BiqYI7_m.js} +1 -1
  84. package/dist/client/assets/{latex-BNC9-sjr.js → latex-81pMfNMt.js} +1 -1
  85. package/dist/client/assets/{line-CyEqpEDp.js → line-DCovs9My.js} +1 -1
  86. package/dist/client/assets/{linear-CXeaA9km.js → linear-cJF5XHE7.js} +1 -1
  87. package/dist/client/assets/{liquid-D-fQw-oJ.js → liquid-sKRTk6dT.js} +1 -1
  88. package/dist/client/assets/{lua-CD2aJ_rS.js → lua-C1uZL4IF.js} +1 -1
  89. package/dist/client/assets/{marko-BQ37hu6z.js → marko-BKEzP1CL.js} +1 -1
  90. package/dist/client/assets/{mdc-B5NUi3zZ.js → mdc-CLkfm94H.js} +1 -1
  91. package/dist/client/assets/{mermaid-parser.core-BxHF_XbX.js → mermaid-parser.core-CTsTbvb2.js} +1 -1
  92. package/dist/client/assets/{mermaid.core-BUtaf4P1.js → mermaid.core-D86HJEwL.js} +3 -3
  93. package/dist/client/assets/{mindmap-definition-RKZ34NQL-D13tPu2o.js → mindmap-definition-RKZ34NQL-CL3heUmL.js} +1 -1
  94. package/dist/client/assets/{nginx-1W1E03Rg.js → nginx-eDGm66pc.js} +1 -1
  95. package/dist/client/assets/{nim-C5A88bFP.js → nim-CoWZPv8-.js} +1 -1
  96. package/dist/client/assets/{perl-BYoP0wNt.js → perl-MoMqtMVr.js} +1 -1
  97. package/dist/client/assets/{php-CFxna09e.js → php-DXXVMAtN.js} +1 -1
  98. package/dist/client/assets/{pieDiagram-4H26LBE5-CHL7Ml5w.js → pieDiagram-4H26LBE5-CWV3TMu4.js} +1 -1
  99. package/dist/client/assets/{pug-BR4JgWAk.js → pug-CPWaB94J.js} +1 -1
  100. package/dist/client/assets/{qml-D1U1EFEe.js → qml-lhvpx8vk.js} +1 -1
  101. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-BnYtv-HY.js → quadrantDiagram-W4KKPZXB-QV25BYos.js} +1 -1
  102. package/dist/client/assets/{r-ChE6X060.js → r-DYbUnmmK.js} +1 -1
  103. package/dist/client/assets/{razor-B5iVfQMe.js → razor-DcyOLv96.js} +1 -1
  104. package/dist/client/assets/{regexp-Dz2drUIf.js → regexp-BdY10jm0.js} +1 -1
  105. package/dist/client/assets/{requirementDiagram-4Y6WPE33-D8QEGLKB.js → requirementDiagram-4Y6WPE33-BPMsmU6J.js} +1 -1
  106. package/dist/client/assets/{review-export-CvFFbCAB.js → review-export-CMwjJURs.js} +1 -1
  107. package/dist/client/assets/{rst-DZM3RGRs.js → rst-6ShFOzgH.js} +1 -1
  108. package/dist/client/assets/{ruby-DkXnm-J8.js → ruby-B04DeVbi.js} +1 -1
  109. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-wVaks6lB.js → sankeyDiagram-5OEKKPKP-DQJeroPp.js} +1 -1
  110. package/dist/client/assets/{sas-DMbpc71c.js → sas-Dj26ftNa.js} +1 -1
  111. package/dist/client/assets/{scss-IwVMMp22.js → scss-BOHpBkgl.js} +1 -1
  112. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-Cg31TB-R.js → sequenceDiagram-3UESZ5HK-DdV0Y6Sz.js} +1 -1
  113. package/dist/client/assets/{shellscript-CIStAKx3.js → shellscript-CpHwjRcU.js} +1 -1
  114. package/dist/client/assets/{shellsession-uLtzHhlo.js → shellsession-BJAvf4GN.js} +1 -1
  115. package/dist/client/assets/{soy-BkxBYigm.js → soy-B67bZJnL.js} +1 -1
  116. package/dist/client/assets/{sql-Ba9y9EvJ.js → sql-8MzOqSsK.js} +1 -1
  117. package/dist/client/assets/{src-9MKexpFu.js → src-AaoRSmFl.js} +1 -1
  118. package/dist/client/assets/{stata-CrPCbiIZ.js → stata-aCME945h.js} +1 -1
  119. package/dist/client/assets/{stateDiagram-AJRCARHV-BbvNjVF6.js → stateDiagram-AJRCARHV-CMD_Xj2M.js} +1 -1
  120. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-vLl7D4ue.js +1 -0
  121. package/dist/client/assets/{surrealql-Dvip5u_o.js → surrealql-B_V_HxAi.js} +1 -1
  122. package/dist/client/assets/{svelte-xBLD60Zd.js → svelte-BcQvTlqz.js} +1 -1
  123. package/dist/client/assets/{templ-CWv68xbP.js → templ-DZCQ2blz.js} +1 -1
  124. package/dist/client/assets/{tex-CHqz-fYs.js → tex-BfeQ5Wuu.js} +1 -1
  125. package/dist/client/assets/{timeline-definition-PNZ67QCA-CWKkJ3QZ.js → timeline-definition-PNZ67QCA-CyIS7Zoe.js} +1 -1
  126. package/dist/client/assets/{ts-tags-DS82EDuE.js → ts-tags-DVWE0E87.js} +1 -1
  127. package/dist/client/assets/{tsx-B2GBjp2F.js → tsx-DdJ7Sfqf.js} +1 -1
  128. package/dist/client/assets/{twig-CC8x9pG0.js → twig-_gVgaha5.js} +1 -1
  129. package/dist/client/assets/{typescript-g7i13lnC.js → typescript-Bj0_LzZV.js} +1 -1
  130. package/dist/client/assets/{vennDiagram-CIIHVFJN-OLItKWeg.js → vennDiagram-CIIHVFJN-C-J2kWyk.js} +1 -1
  131. package/dist/client/assets/{vue-rFbe7luB.js → vue-Dnt_GBRb.js} +1 -1
  132. package/dist/client/assets/{vue-html-D9GQtYub.js → vue-html-ClVA5__5.js} +1 -1
  133. package/dist/client/assets/{vue-vine-mrNtQtY5.js → vue-vine-BCcz4SVP.js} +1 -1
  134. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Dy1yfeb4.js → wardleyDiagram-YWT4CUSO-Dzt4EPh8.js} +1 -1
  135. package/dist/client/assets/{xml-CHfMjyAM.js → xml-BYeUHEti.js} +1 -1
  136. package/dist/client/assets/{xsl-BFkNSogJ.js → xsl-Vsx0SZEV.js} +1 -1
  137. package/dist/client/assets/{xychartDiagram-2RQKCTM6-DfSnfjVL.js → xychartDiagram-2RQKCTM6-BAWZKvwP.js} +1 -1
  138. package/dist/client/assets/{yaml-BfSgHc04.js → yaml-C6L1khMK.js} +1 -1
  139. package/dist/client/index.html +2 -2
  140. package/dist/{completions-BO2DUM-8.mjs → completions-DvyV49HY.mjs} +1 -0
  141. package/dist/{doctor-D0Y3kOY7.mjs → doctor-Bz9VHuBI.mjs} +7 -7
  142. package/dist/{find-tui-binary-B71xiwWu.mjs → find-tui-binary-DVQADOSF.mjs} +56 -25
  143. package/dist/{git-Czo96ymM.mjs → git-BGj31GX-.mjs} +71 -7
  144. package/dist/git-CfDSkUcE.mjs +2 -0
  145. package/dist/{github-CErBub2y.mjs → github-DXiEeHzk.mjs} +1 -1
  146. package/dist/{github-DBsZ0h_l.mjs → github-DpzqNrUh.mjs} +3 -3
  147. package/dist/{github-attachments-plDeB0iE.mjs → github-attachments-DgOf7BhP.mjs} +2 -2
  148. package/dist/{mcp-DtVrMR2S.mjs → mcp-zDVzU1vl.mjs} +32 -29
  149. package/dist/native/tui-darwin-arm64/diffing-tui +0 -0
  150. package/dist/native/tui-darwin-x64/diffing-tui +0 -0
  151. package/dist/native/tui-linux-arm64-gnu/diffing-tui +0 -0
  152. package/dist/native/tui-linux-arm64-musl/diffing-tui +0 -0
  153. package/dist/native/tui-linux-x64-gnu/diffing-tui +0 -0
  154. package/dist/native/tui-linux-x64-musl/diffing-tui +0 -0
  155. package/dist/native/tui-win32-x64-msvc/diffing-tui.exe +0 -0
  156. package/dist/{search-BMPY_ZW8.mjs → search-3R2E5xxr.mjs} +16 -1
  157. package/dist/{search-BO9Im7eu.mjs → search-CQ4nsjBX.mjs} +1 -1
  158. package/dist/{server-j0PnTVX1.mjs → server-Dw3lkQ5q.mjs} +157 -42
  159. package/dist/{server-lock-CY0_1mcS.mjs → server-lock-BNI8FKV1.mjs} +175 -23
  160. package/dist/{session-conflict-C6V9ZKo7.mjs → session-conflict-Bqt1M4Mp.mjs} +7 -7
  161. package/dist/{session-manager-CYNchhVA.mjs → session-manager-BKSZQqDJ.mjs} +2 -2
  162. package/dist/session-url-sr7lXXVc.mjs +100 -0
  163. package/dist/{tui-search-bridge-Bfb2ktdA.mjs → tui-search-bridge-BGgLCwMF.mjs} +3 -3
  164. package/dist/{update-check-Copcz9eb.mjs → update-check-BUfh4Y6c.mjs} +16 -15
  165. package/package.json +4 -1
  166. package/dist/client/assets/channel-Ct4-oSQN.js +0 -1
  167. package/dist/client/assets/chunk-QZHKN3VN-BXhKFVX7.js +0 -1
  168. package/dist/client/assets/chunk-WU5MYG2G-_EwuC51_.js +0 -1
  169. package/dist/client/assets/classDiagram-4FO5ZUOK-C8bdx9R4.js +0 -1
  170. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B26wrQuH.js +0 -1
  171. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-B5BbZkU5.js +0 -1
  172. package/dist/git-DaP_1rVy.mjs +0 -2
  173. package/dist/settings-yK0GYpbn.mjs +0 -60
@@ -1,7 +1,8 @@
1
- import { i as buildGitDiffArgs, s as parseDiffOptions, t as startServer } from "./server-j0PnTVX1.mjs";
1
+ import { i as buildGitDiffArgs, s as parseDiffOptions, t as startServer } from "./server-Dw3lkQ5q.mjs";
2
+ import { i as reviewSessionUrl, n as joinSessionApiUrl, r as reviewSessionBaseUrl, t as appendSessionToken } from "./session-url-sr7lXXVc.mjs";
2
3
  import { t as formatComments } from "./comment-format-B85NHZnG.mjs";
3
4
  import { n as formatPlanReview } from "./plan-format-BwJh5JSE.mjs";
4
- import { c as removeServerLockIfOwned, i as isLockAlive, p as writeServerLock, r as diffScopeKey, s as removeServerLock, t as acquireServerStartupLease, u as resolveActiveServerLock } from "./server-lock-CY0_1mcS.mjs";
5
+ import { c as removeServerLockIfOwned, h as SESSION_TOKEN_HEADER, i as isLockAlive, p as writeServerLock, r as diffScopeKey, s as removeServerLock, t as acquireServerStartupLease, u as resolveActiveServerLock, x as isLoopbackHost, y as generateSessionToken } from "./server-lock-BNI8FKV1.mjs";
5
6
  import { n as AWAIT_REVIEW_TIMEOUT_NEXT_ACTION, r as AWAIT_TOOL_DESCRIPTION_SUFFIX, s as PLAN_SUBMIT_NEXT_ACTION, t as AWAIT_PLAN_TIMEOUT_NEXT_ACTION } from "./handoff-LAFtmnHf.mjs";
6
7
  import { execFileSync } from "node:child_process";
7
8
  import { randomUUID } from "node:crypto";
@@ -105,25 +106,18 @@ function resolveMcpRepository(repoPath = process.cwd(), explicit = false) {
105
106
  throw new Error(`diffing mcp: path is not inside a Git repository: ${candidate}`);
106
107
  }
107
108
  }
108
- function isLoopbackHost(host) {
109
- const normalized = host.toLowerCase();
110
- if (normalized === "localhost" || normalized === "::1" || normalized === "[::1]") return true;
111
- const octets = normalized.split(".");
112
- return octets.length === 4 && octets[0] === "127" && octets.every((part) => {
113
- if (!/^\d{1,3}$/.test(part)) return false;
114
- const value = Number(part);
115
- return value >= 0 && value <= 255;
116
- });
117
- }
118
109
  function lockUrl(lock) {
119
- if (lock.port <= 0) return null;
120
- if (!isLoopbackHost(lock.host)) return null;
121
- return `http://${lock.host === "::1" ? "[::1]" : lock.host}:${lock.port}`;
110
+ return reviewSessionUrl(lock);
122
111
  }
123
- async function requestJson(base, path, init) {
112
+ async function requestJson(base, path, init, authToken) {
124
113
  let response;
125
114
  try {
126
- response = await fetch(`${base}${path}`, init);
115
+ const headers = new Headers(init?.headers);
116
+ if (authToken) headers.set(SESSION_TOKEN_HEADER, authToken);
117
+ response = await fetch(joinSessionApiUrl(base, path), {
118
+ ...init,
119
+ headers
120
+ });
127
121
  } catch (error) {
128
122
  if (error instanceof Error && error.name === "AbortError") throw new Error(`Request to ${path} was cancelled. Retry the MCP tool when ready.`);
129
123
  const detail = error instanceof Error ? error.message : String(error);
@@ -368,11 +362,11 @@ function createMcpServer(options) {
368
362
  const lock = liveLock();
369
363
  if (!lock) throw new Error(`No diffing review session is running for ${repoRoot}. Start one with start_review_session, \`diffing --web\`, or \`diffing "gh pr <ref>"\`, then retry.`);
370
364
  ensureReusableLock(lock);
371
- const url = lockUrl(lock);
372
- if (!url) throw new Error("The active diffing session does not expose a reachable loopback API.");
365
+ const apiOrigin = reviewSessionBaseUrl(lock);
366
+ if (!apiOrigin) throw new Error("The active diffing session does not expose a reachable loopback API.");
373
367
  return {
374
368
  lock,
375
- url,
369
+ apiOrigin,
376
370
  identity: `${lock.pid}:${lock.startedAt}:${lock.port}:${lock.ownerId ?? ""}`
377
371
  };
378
372
  }
@@ -391,11 +385,11 @@ function createMcpServer(options) {
391
385
  if (session.lock.mode === "tui") {
392
386
  if (!session.lock.capability) throw new Error("The TUI lock is missing its API capability.");
393
387
  headers.set("X-Diffing-Capability", session.lock.capability);
394
- }
395
- return requestJson(session.url, path, {
388
+ } else if (session.lock.authToken) headers.set(SESSION_TOKEN_HEADER, session.lock.authToken);
389
+ return requestJson(session.apiOrigin, path, {
396
390
  ...init,
397
391
  headers
398
- });
392
+ }, session.lock.authToken);
399
393
  }
400
394
  function requestBaseJson(path, init) {
401
395
  return requestSessionJson(requireWebSession(), path, init);
@@ -530,12 +524,17 @@ function createMcpServer(options) {
530
524
  try {
531
525
  const afterLease = liveLock();
532
526
  if (afterLease) return reuse(afterLease);
527
+ const authToken = generateSessionToken();
533
528
  const lock = {
534
529
  port: (await startServerFn({
535
530
  port: 0,
536
531
  host: "127.0.0.1",
537
532
  clientDir,
538
- diffOpts: parsed
533
+ diffOpts: parsed,
534
+ security: {
535
+ bindHost: "127.0.0.1",
536
+ authToken
537
+ }
539
538
  })).port,
540
539
  host: "127.0.0.1",
541
540
  pid: process.pid,
@@ -547,7 +546,8 @@ function createMcpServer(options) {
547
546
  diffArgs: [...diffArgs],
548
547
  owner: "mcp",
549
548
  ownerId,
550
- sessionId: ownerId
549
+ sessionId: ownerId,
550
+ authToken
551
551
  };
552
552
  try {
553
553
  writeLock(lock);
@@ -749,7 +749,9 @@ function createMcpServer(options) {
749
749
  if (author) params.set("author", author);
750
750
  if (fullBody) params.set("fullBody", "true");
751
751
  if (format === "xml") {
752
- const res = await fetch(`${session.url}/api/gh/threads?${params}`);
752
+ const headers = new Headers();
753
+ if (session.lock.authToken) headers.set(SESSION_TOKEN_HEADER, session.lock.authToken);
754
+ const res = await fetch(joinSessionApiUrl(session.apiOrigin, `/api/gh/threads?${params}`), { headers });
753
755
  const text = await res.text();
754
756
  if (!res.ok) throw new Error(text || res.statusText);
755
757
  return textResult(text, { result: {
@@ -784,7 +786,9 @@ function createMcpServer(options) {
784
786
  if (fullBody) params.set("fullBody", "true");
785
787
  if (state) params.set("state", state);
786
788
  if (format === "xml") {
787
- const res = await fetch(`${session.url}/api/gh/reviews?${params}`);
789
+ const headers = new Headers();
790
+ if (session.lock.authToken) headers.set(SESSION_TOKEN_HEADER, session.lock.authToken);
791
+ const res = await fetch(joinSessionApiUrl(session.apiOrigin, `/api/gh/reviews?${params}`), { headers });
788
792
  const text = await res.text();
789
793
  if (!res.ok) throw new Error(text || res.statusText);
790
794
  return textResult(text, { result: {
@@ -1253,7 +1257,6 @@ function createMcpServer(options) {
1253
1257
  annotations: MUTATING
1254
1258
  }, async ({ title, body, source, model, planId }) => {
1255
1259
  const session = requireWebSession();
1256
- const base = session.url;
1257
1260
  await seedPlanCursor(session, void 0, true);
1258
1261
  const plan = await requestSessionJson(session, "/api/plans", {
1259
1262
  method: "POST",
@@ -1266,7 +1269,7 @@ function createMcpServer(options) {
1266
1269
  model
1267
1270
  })
1268
1271
  });
1269
- const url = `${base}/plan/${plan.id}`;
1272
+ const url = appendSessionToken(`${session.apiOrigin}/plan/${plan.id}`, session.lock.authToken);
1270
1273
  return textResult(`Submitted plan ${plan.id} (v${plan.version}) at ${url}. ${PLAN_SUBMIT_NEXT_ACTION}`, {
1271
1274
  status: "submitted",
1272
1275
  planId: plan.id,
@@ -1,4 +1,4 @@
1
- import { d as getProjectStorageDir, p as getRepoRoot } from "./git-Czo96ymM.mjs";
1
+ import { f as getProjectStorageDir, h as getRepoRoot } from "./git-BGj31GX-.mjs";
2
2
  import { join } from "node:path";
3
3
  import { mkdirSync } from "node:fs";
4
4
  //#region src/lib/symbols.ts
@@ -38,6 +38,11 @@ const SYMBOL_PATTERNS = [
38
38
  kind: "enum",
39
39
  nameGroup: 1
40
40
  },
41
+ {
42
+ pattern: /^\s*namespace\s+((?:\w[\w$]*(?:\\\w[\w$]*)*)+)\s*;/i,
43
+ kind: "namespace",
44
+ nameGroup: 1
45
+ },
41
46
  {
42
47
  pattern: /^\s*(?:(?:export|declare)\s+)*namespace\s+(\w[\w$]*)/i,
43
48
  kind: "namespace",
@@ -48,6 +53,16 @@ const SYMBOL_PATTERNS = [
48
53
  kind: "variable",
49
54
  nameGroup: 1
50
55
  },
56
+ {
57
+ pattern: /^\s*(?:(?:public|private|protected|static|abstract|final)\s+)+function\s+(\w[\w$]*)\s*\(/i,
58
+ kind: "function",
59
+ nameGroup: 1
60
+ },
61
+ {
62
+ pattern: /^\s*(?:(?:abstract|final|readonly)\s+)+class\s+(\w[\w$]*)/i,
63
+ kind: "class",
64
+ nameGroup: 1
65
+ },
51
66
  {
52
67
  pattern: /^\s*(?!(?:if|for|while|switch|catch)\b)(?:(?:public|private|protected|static|async|abstract|readonly|override|get|set)\s+)*(\w[\w$]*)\s*(?:<[^>]+>)?\s*\([^)]*\)\s*(?:\{|:[^={]+[;{])/i,
53
68
  kind: "method",
@@ -1,2 +1,2 @@
1
- import { a as searchFiles, i as searchContent, o as searchSymbols, r as searchAll, s as trackSelection } from "./search-BMPY_ZW8.mjs";
1
+ import { a as searchFiles, i as searchContent, o as searchSymbols, r as searchAll, s as trackSelection } from "./search-3R2E5xxr.mjs";
2
2
  export { searchAll, searchContent, searchFiles, searchSymbols, trackSelection };
@@ -1,9 +1,10 @@
1
- import { C as isSafePath, S as revertHunk, _ as getUntrackedFilePathsAsync, a as getCustomGitDiffAsync, b as listRepoFiles, c as getGitDiffAsync, d as getProjectStorageDir, f as getRepoName, g as getTabSizeForFiles, h as getShowDiff, i as getCommitSeriesSummary, l as getHunkHistory, o as getFileContent, p as getRepoRoot, r as getBranchName, u as getMergeStatus, v as gitAddFile, w as toSafeRelativePath, y as isGitRepo } from "./git-Czo96ymM.mjs";
2
- import { a as searchFiles, i as searchContent, o as searchSymbols, r as searchAll, s as trackSelection, t as getSearchStatus } from "./search-BMPY_ZW8.mjs";
3
- import { n as saveSettings, t as loadSettings } from "./settings-yK0GYpbn.mjs";
1
+ import { C as listRepoFiles, D as toSafeRelativePath, E as isSafePath, S as isGitRepo, T as revertHunk, _ as getShowDiff, a as getCommitSeriesSummary, b as getUntrackedFilePathsAsync, d as getMergeStatus, f as getProjectStorageDir, h as getRepoRoot, l as getGitDiffAsync, m as getRepoMetadataAsync, o as getCustomGitDiffAsync, s as getFileContent, u as getHunkHistory, x as gitAddFile, y as getTabSizeForFilesAsync } from "./git-BGj31GX-.mjs";
2
+ import { a as searchFiles, i as searchContent, o as searchSymbols, r as searchAll, s as trackSelection, t as getSearchStatus } from "./search-3R2E5xxr.mjs";
3
+ import { a as loadSettings, o as saveSettings } from "./session-url-sr7lXXVc.mjs";
4
4
  import { t as formatComments } from "./comment-format-B85NHZnG.mjs";
5
5
  import { n as formatPlanReview, r as sectionTitleForLine, t as extractPlanLines } from "./plan-format-BwJh5JSE.mjs";
6
- import { D as updatePrReviewComment, E as submitReview, S as refreshPrSession, T as setPrReviewThreadResolved, a as detectCwdRepo, b as parsePrRef, f as fetchPrFileContentViaGh, i as deletePrReviewComment, l as fetchExistingCommentsViaGh, t as buildPrSession, u as fetchExistingReviewsViaGh, w as resolvedFromSession } from "./github-DBsZ0h_l.mjs";
6
+ import { _ as buildSessionTokenSetCookieValue, b as injectSessionTokenIntoHtml, v as createServerAuthMiddleware } from "./server-lock-BNI8FKV1.mjs";
7
+ import { D as updatePrReviewComment, E as submitReview, S as refreshPrSession, T as setPrReviewThreadResolved, a as detectCwdRepo, b as parsePrRef, f as fetchPrFileContentViaGh, i as deletePrReviewComment, l as fetchExistingCommentsViaGh, t as buildPrSession, u as fetchExistingReviewsViaGh, w as resolvedFromSession } from "./github-DpzqNrUh.mjs";
7
8
  import { execFileSync } from "node:child_process";
8
9
  import { createHash } from "node:crypto";
9
10
  import { fileURLToPath } from "node:url";
@@ -53,6 +54,7 @@ const DEFAULTS = {
53
54
  outputMode: "auto",
54
55
  host: "127.0.0.1",
55
56
  noOpen: false,
57
+ insecureNoAuth: false,
56
58
  reuseSession: false,
57
59
  replaceSession: false,
58
60
  help: false,
@@ -184,6 +186,10 @@ const DIFFING_OPTIONS = {
184
186
  type: "boolean",
185
187
  default: false
186
188
  },
189
+ "insecure-no-auth": {
190
+ type: "boolean",
191
+ default: false
192
+ },
187
193
  "reuse-session": {
188
194
  type: "boolean",
189
195
  default: false
@@ -241,8 +247,12 @@ Git Diff Options (drop-in replacement for git diff):`);
241
247
  console.log(`
242
248
  Diffing Server Options:
243
249
  --port <port> Port to run the server on (default: random available port)
244
- --host <host> Host address to bind to (default: 127.0.0.1). Pass
245
- 0.0.0.0 to expose the server to the local network.
250
+ --host <host> Host address to bind to (default: 127.0.0.1). Loopback
251
+ binds require a per-session API token. To expose the
252
+ review UI on your LAN, pass 0.0.0.0 together with
253
+ --insecure-no-auth (disables API authentication).
254
+ --insecure-no-auth Allow binding to 0.0.0.0 without API tokens (unsafe on
255
+ shared networks). Ignored on loopback binds.
246
256
  --no-open Don't open the browser automatically
247
257
  --reuse-session Open the active review instead of starting another
248
258
  --replace-session Stop the active review and start a replacement
@@ -300,7 +310,8 @@ Examples:
300
310
  diffing -U10 Diff with 10 context lines
301
311
  diffing --word-diff=color Word-level diff in color
302
312
  diffing -b -w Ignore whitespace changes
303
- diffing --host 0.0.0.0 Allow other machines on the LAN to review
313
+ diffing --host 0.0.0.0 --insecure-no-auth
314
+ Expose the review UI on the LAN without API tokens
304
315
  diffing view Browse the working-tree diff in the TUI
305
316
  diffing view --staged Browse staged changes
306
317
  diffing --view main..feature Browse a branch comparison
@@ -454,6 +465,15 @@ function preprocessOptionalValueArgs(rawArgs) {
454
465
  "find-renames",
455
466
  "break-rewrites"
456
467
  ]);
468
+ /** Git accepts values only as `--flag=value` for these; never `--flag value`. */
469
+ const ATTACHED_ONLY_LONGS = new Set([
470
+ "stat",
471
+ "dirstat",
472
+ "relative",
473
+ "word-diff",
474
+ "color-moved",
475
+ "submodule"
476
+ ]);
457
477
  const startsWithDigit = (s) => typeof s === "string" && /^[0-9]/.test(s);
458
478
  const out = [];
459
479
  for (let i = 0; i < rawArgs.length; i++) {
@@ -482,6 +502,13 @@ function preprocessOptionalValueArgs(rawArgs) {
482
502
  }
483
503
  continue;
484
504
  }
505
+ const attachedOnlyMatch = /^--(stat|dirstat|relative|word-diff|color-moved|submodule)$/.exec(arg);
506
+ if (attachedOnlyMatch) {
507
+ const name = attachedOnlyMatch[1];
508
+ if (ATTACHED_ONLY_LONGS.has(name)) out.push(`--${name}=`);
509
+ else out.push(arg);
510
+ continue;
511
+ }
485
512
  out.push(arg);
486
513
  }
487
514
  return out;
@@ -517,6 +544,7 @@ function parseDiffOptions(rawArgs, defaultInteractiveMode = "web") {
517
544
  if (values.port) opts.port = parseInt(values.port, 10);
518
545
  if (values.host) opts.host = values.host;
519
546
  if (values["no-open"]) opts.noOpen = true;
547
+ if (values["insecure-no-auth"]) opts.insecureNoAuth = true;
520
548
  if (values["reuse-session"]) opts.reuseSession = true;
521
549
  if (values["replace-session"]) opts.replaceSession = true;
522
550
  if (values["gh-pr"]) opts.ghPr = String(values["gh-pr"]);
@@ -594,7 +622,11 @@ function parseDiffOptions(rawArgs, defaultInteractiveMode = "web") {
594
622
  if (values.raw) opts.outputFormat = "raw";
595
623
  if (values.numstat) opts.outputFormat = "numstat";
596
624
  if (values.shortstat) opts.outputFormat = "shortstat";
597
- if (values.stat !== void 0) opts.outputFormat = "stat";
625
+ if (values.stat !== void 0) {
626
+ opts.outputFormat = "stat";
627
+ const statVal = values.stat;
628
+ if (statVal) opts.statParam = statVal;
629
+ }
598
630
  if (values.summary) opts.outputFormat = "summary";
599
631
  if (values["name-only"]) opts.outputFormat = "name-only";
600
632
  if (values["name-status"]) opts.outputFormat = "name-status";
@@ -654,11 +686,9 @@ function parseDiffOptions(rawArgs, defaultInteractiveMode = "web") {
654
686
  }
655
687
  const dashDashIdx = rawArgs.indexOf("--");
656
688
  if (dashDashIdx >= 0) {
657
- for (let i = 0; i < dashDashIdx; i++) {
658
- const arg = rawArgs[i];
659
- if (!arg.startsWith("-")) opts.revisions.push(arg);
660
- }
661
689
  for (let i = dashDashIdx + 1; i < rawArgs.length; i++) opts.pathspecs.push(rawArgs[i]);
690
+ const pathspecSet = new Set(opts.pathspecs);
691
+ for (const p of positionals) if (!pathspecSet.has(p)) opts.revisions.push(p);
662
692
  } else for (const p of positionals) opts.revisions.push(p);
663
693
  if (values.view) opts.outputMode = "tui";
664
694
  else if (values.tui) opts.outputMode = "tui";
@@ -707,7 +737,7 @@ function buildGitDiffArgs(opts) {
707
737
  if (opts.outputFormat === "raw") args.push("--raw");
708
738
  if (opts.outputFormat === "numstat") args.push("--numstat");
709
739
  if (opts.outputFormat === "shortstat") args.push("--shortstat");
710
- if (opts.outputFormat === "stat") args.push("--stat");
740
+ if (opts.outputFormat === "stat") args.push(opts.statParam ? `--stat=${opts.statParam}` : "--stat");
711
741
  if (opts.outputFormat === "summary") args.push("--summary");
712
742
  if (opts.outputFormat === "name-only") args.push("--name-only");
713
743
  if (opts.outputFormat === "name-status") args.push("--name-status");
@@ -781,6 +811,88 @@ function intoShowMode(opts) {
781
811
  return opts;
782
812
  }
783
813
  //#endregion
814
+ //#region src/lib/git-path.ts
815
+ /** Decode Git `core.quotePath` C-quoted pathnames from diff headers. */
816
+ function decodeGitPath$1(raw) {
817
+ const input = raw.trim();
818
+ if (!(input.startsWith("\"") && input.endsWith("\""))) return input;
819
+ const bytes = [];
820
+ const pushText = (value) => bytes.push(...Buffer.from(value, "utf8"));
821
+ for (let i = 1; i < input.length - 1; i++) {
822
+ if (input[i] !== "\\") {
823
+ const codePoint = input.codePointAt(i);
824
+ pushText(String.fromCodePoint(codePoint));
825
+ if (codePoint > 65535) i++;
826
+ continue;
827
+ }
828
+ const escaped = input[++i];
829
+ if (escaped == null) break;
830
+ const simple = {
831
+ a: 7,
832
+ b: 8,
833
+ t: 9,
834
+ n: 10,
835
+ v: 11,
836
+ f: 12,
837
+ r: 13,
838
+ "\"": 34,
839
+ "\\": 92
840
+ };
841
+ if (escaped in simple) {
842
+ bytes.push(simple[escaped]);
843
+ continue;
844
+ }
845
+ if (/[0-7]/.test(escaped)) {
846
+ let octal = escaped;
847
+ while (octal.length < 3 && i + 1 < input.length - 1 && /[0-7]/.test(input[i + 1])) octal += input[++i];
848
+ bytes.push(Number.parseInt(octal, 8));
849
+ continue;
850
+ }
851
+ pushText(escaped);
852
+ }
853
+ return Buffer.from(bytes).toString("utf8");
854
+ }
855
+ function stripSidePrefix$1(path, prefix) {
856
+ return path.startsWith(prefix) ? path.slice(prefix.length) : path;
857
+ }
858
+ function consumeGitToken$1(input, start) {
859
+ if (input[start] !== "\"") {
860
+ const end = input.indexOf(" ", start);
861
+ return {
862
+ token: input.slice(start, end < 0 ? input.length : end),
863
+ next: end < 0 ? input.length : end
864
+ };
865
+ }
866
+ let escaped = false;
867
+ for (let i = start + 1; i < input.length; i++) {
868
+ const char = input[i];
869
+ if (!escaped && char === "\"") return {
870
+ token: input.slice(start, i + 1),
871
+ next: i + 1
872
+ };
873
+ if (!escaped && char === "\\") escaped = true;
874
+ else escaped = false;
875
+ }
876
+ return null;
877
+ }
878
+ /** Parse `diff --git` header paths, including quoted paths and spaces in names. */
879
+ function parseGitDiffHeaderPaths(line) {
880
+ if (!line.startsWith("diff --git ")) return null;
881
+ const rest = line.slice(11);
882
+ if (rest.startsWith("\"")) {
883
+ const first = consumeGitToken$1(rest, 0);
884
+ if (!first) return null;
885
+ let cursor = first.next;
886
+ while (cursor < rest.length && /\s/.test(rest[cursor])) cursor++;
887
+ const second = consumeGitToken$1(rest, cursor);
888
+ if (!second) return null;
889
+ return [stripSidePrefix$1(decodeGitPath$1(first.token), "a/"), stripSidePrefix$1(decodeGitPath$1(second.token), "b/")];
890
+ }
891
+ const separator = rest.lastIndexOf(" b/");
892
+ if (separator < 0) return null;
893
+ return [stripSidePrefix$1(rest.slice(0, separator), "a/"), stripSidePrefix$1(rest.slice(separator + 1), "b/")];
894
+ }
895
+ //#endregion
784
896
  //#region src/lib/diff-overview.ts
785
897
  /**
786
898
  * Compose the working-tree banner. Used by the default `git diff` (unstaged +
@@ -973,7 +1085,6 @@ function summariseCommitSeries(series, rows) {
973
1085
  }
974
1086
  //#endregion
975
1087
  //#region src/lib/diff-engine.ts
976
- const MAX_BUFFER = 50 * 1024 * 1024;
977
1088
  /**
978
1089
  * Determine whether to use the "standard" web mode (unstaged+staged+untracked)
979
1090
  * or a "custom" mode (specific revisions / pathspecs).
@@ -988,8 +1099,8 @@ function isCustomMode$1(opts) {
988
1099
  function parseFilePaths(patch) {
989
1100
  const paths = /* @__PURE__ */ new Set();
990
1101
  for (const line of patch.split("\n")) {
991
- const match = line.match(/^diff --git a\/.+ b\/(.+)$/);
992
- if (match) paths.add(match[1]);
1102
+ const parsed = parseGitDiffHeaderPaths(line);
1103
+ if (parsed) paths.add(parsed[1]);
993
1104
  }
994
1105
  return [...paths];
995
1106
  }
@@ -1001,9 +1112,9 @@ function parseBinaryFiles(patch, untrackedFiles) {
1001
1112
  if (!line.startsWith("Binary files ") || !line.includes(" differ")) continue;
1002
1113
  let filePath = "";
1003
1114
  for (let j = i - 1; j >= 0; j--) {
1004
- const match = lines[j].match(/^diff --git a\/.+ b\/(.+)$/);
1005
- if (match) {
1006
- filePath = match[1];
1115
+ const parsed = parseGitDiffHeaderPaths(lines[j]);
1116
+ if (parsed) {
1117
+ filePath = parsed[1];
1007
1118
  break;
1008
1119
  }
1009
1120
  }
@@ -1068,12 +1179,10 @@ async function executeDiffAsync(opts) {
1068
1179
  */
1069
1180
  async function executeDiffWithMeta(opts) {
1070
1181
  const { patch, commits, truncated } = await executeDiffAsync(opts);
1071
- const repoName = getRepoName();
1072
- const branch = getBranchName();
1073
- const untrackedFiles = opts.includeUntracked && !opts.showMode ? await getUntrackedFilePathsAsync() : [];
1182
+ const [{ repoName, branch }, untrackedFiles] = await Promise.all([getRepoMetadataAsync(), opts.includeUntracked && !opts.showMode ? getUntrackedFilePathsAsync() : Promise.resolve([])]);
1074
1183
  const binaryFiles = parseBinaryFiles(patch, new Set(untrackedFiles));
1075
1184
  const filePaths = parseFilePaths(patch);
1076
- const tabSizeMap = getTabSizeForFiles(filePaths);
1185
+ const tabSizeMap = await getTabSizeForFilesAsync(filePaths);
1077
1186
  let overview;
1078
1187
  if (opts.showMode && commits && commits.length > 0) overview = buildCommitOverview({
1079
1188
  commits: commits.map((c) => ({
@@ -1150,11 +1259,7 @@ function runTerminalDiff(opts) {
1150
1259
  }
1151
1260
  finalArgs.push(...args);
1152
1261
  try {
1153
- execFileSync("git", ["diff", ...finalArgs], {
1154
- encoding: "utf-8",
1155
- maxBuffer: MAX_BUFFER,
1156
- stdio: "inherit"
1157
- });
1262
+ execFileSync("git", ["diff", ...finalArgs], { stdio: "inherit" });
1158
1263
  return 0;
1159
1264
  } catch (err) {
1160
1265
  if (err.status === 1 && opts.exitCode) return 1;
@@ -1175,11 +1280,7 @@ function runTerminalShow(opts) {
1175
1280
  ];
1176
1281
  if (opts.pathspecs.length > 0) args.push("--", ...opts.pathspecs);
1177
1282
  try {
1178
- execFileSync("git", args, {
1179
- encoding: "utf-8",
1180
- maxBuffer: MAX_BUFFER,
1181
- stdio: "inherit"
1182
- });
1283
+ execFileSync("git", args, { stdio: "inherit" });
1183
1284
  return 0;
1184
1285
  } catch (err) {
1185
1286
  return err.status ?? 1;
@@ -1683,7 +1784,7 @@ function guiEditorCommand(bin, absolutePath, platform) {
1683
1784
  function terminalEditorCommand(bin, absolutePath, platform, env) {
1684
1785
  if (platform === "darwin") return {
1685
1786
  cmd: "osascript",
1686
- args: ["-e", `tell application "Terminal" to do script "${bin} \\"${absolutePath.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}\\""`]
1787
+ args: ["-e", `tell application "Terminal" to do script ("${bin} " & quoted form of "${absolutePath.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}")`]
1687
1788
  };
1688
1789
  if (platform === "win32") return {
1689
1790
  cmd: "cmd.exe",
@@ -2835,8 +2936,13 @@ function collectPrAvatarUrls(session) {
2835
2936
  function isCustomMode(opts) {
2836
2937
  return opts.revisions.length > 0 || opts.pathspecs.length > 0 || opts.showMode;
2837
2938
  }
2838
- function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore, prSessionStore, prMode = false) {
2939
+ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore, prSessionStore, prMode = false, security = {
2940
+ bindHost: "127.0.0.1",
2941
+ authToken: null,
2942
+ insecureNoAuth: true
2943
+ }) {
2839
2944
  const app = new Hono();
2945
+ app.use("*", createServerAuthMiddleware(security));
2840
2946
  let diffOpts = { ...diffOptsInput };
2841
2947
  const customMode = isCustomMode(diffOpts);
2842
2948
  const store = commentStore ?? new FileCommentStore();
@@ -3733,7 +3839,7 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
3733
3839
  const session = await prStore.get();
3734
3840
  if (!session) return notInPrMode(c);
3735
3841
  try {
3736
- const { fetchPrChecks } = await import("./github-CErBub2y.mjs");
3842
+ const { fetchPrChecks } = await import("./github-DXiEeHzk.mjs");
3737
3843
  const checks = await fetchPrChecks(resolvedFromSession(session), session.headSha);
3738
3844
  const summary = {
3739
3845
  total: checks.length,
@@ -3765,7 +3871,7 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
3765
3871
  const text = typeof body.body === "string" ? body.body.trim() : "";
3766
3872
  if (!text) return c.json({ error: "body is required" }, 400);
3767
3873
  try {
3768
- const { replyToPrComment } = await import("./github-CErBub2y.mjs");
3874
+ const { replyToPrComment } = await import("./github-DXiEeHzk.mjs");
3769
3875
  const result = await replyToPrComment({
3770
3876
  resolved: resolvedFromSession(session),
3771
3877
  inReplyTo: id,
@@ -3979,8 +4085,8 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
3979
4085
  if (decision !== "approve" && decision !== "comment" && decision !== "request-changes" && decision !== "draft") return c.json({ error: "decision must be one of: approve, comment, request-changes, draft" }, 400);
3980
4086
  const generalBody = typeof body.body === "string" ? body.body : "";
3981
4087
  if (body.dryRun === true) {
3982
- const { buildReviewPayload, resolvedFromSession } = await import("./github-CErBub2y.mjs");
3983
- const { rewriteLocalAttachmentsInBodies } = await import("./github-attachments-plDeB0iE.mjs");
4088
+ const { buildReviewPayload, resolvedFromSession } = await import("./github-DXiEeHzk.mjs");
4089
+ const { rewriteLocalAttachmentsInBodies } = await import("./github-attachments-DgOf7BhP.mjs");
3984
4090
  const resolved = resolvedFromSession(session);
3985
4091
  const comments = session.comments ?? [];
3986
4092
  const rewritten = await rewriteLocalAttachmentsInBodies(resolved, [generalBody, ...comments.map((c) => c.body ?? "")], { dryRun: true });
@@ -4370,10 +4476,19 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
4370
4476
  try {
4371
4477
  const content = await readFile(fullPath);
4372
4478
  const contentType = MIME_TYPES[extname(fullPath)] || "application/octet-stream";
4479
+ if (contentType === "text/html" && security.authToken) {
4480
+ const html = injectSessionTokenIntoHtml(content.toString("utf-8"), security.authToken);
4481
+ return new Response(html, { headers: {
4482
+ "Content-Type": contentType,
4483
+ "Set-Cookie": buildSessionTokenSetCookieValue(security.authToken)
4484
+ } });
4485
+ }
4373
4486
  return new Response(content, { headers: { "Content-Type": contentType } });
4374
4487
  } catch {
4375
- const indexContent = await readFile(join(clientDir, "index.html"));
4376
- return new Response(indexContent, { headers: { "Content-Type": "text/html" } });
4488
+ const html = injectSessionTokenIntoHtml((await readFile(join(clientDir, "index.html"))).toString("utf-8"), security.authToken);
4489
+ const spaHeaders = { "Content-Type": "text/html" };
4490
+ if (security.authToken) spaHeaders["Set-Cookie"] = buildSessionTokenSetCookieValue(security.authToken);
4491
+ return new Response(html, { headers: spaHeaders });
4377
4492
  }
4378
4493
  });
4379
4494
  return app;
@@ -4464,7 +4579,7 @@ async function startServer(options) {
4464
4579
  throw new Error(`Failed to build PR session for ${options.prRef}: ${detail}`);
4465
4580
  }
4466
4581
  }
4467
- const app = createApp(options.clientDir, options.diffOpts, void 0, void 0, void 0, prMode);
4582
+ const app = createApp(options.clientDir, options.diffOpts, void 0, void 0, void 0, prMode, options.security);
4468
4583
  return new Promise((resolve) => {
4469
4584
  serve({
4470
4585
  fetch: app.fetch,