diffing 0.10.5 → 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 (182) hide show
  1. package/README.md +76 -41
  2. package/dist/{cli-agent-BJiATn11.mjs → cli-agent-CWsOHN-j.mjs} +198 -57
  3. package/dist/{cli-gh-_bkDCxhh.mjs → cli-gh-DI69gJGo.mjs} +27 -17
  4. package/dist/cli.mjs +189 -229
  5. package/dist/client/assets/{angular-html-CBcwKYDC.js → angular-html-PLPuQo0k.js} +1 -1
  6. package/dist/client/assets/{angular-ts-DRBYUaJA.js → angular-ts-CE02Ij4b.js} +1 -1
  7. package/dist/client/assets/{apl-BM0X8jeL.js → apl-CsuUKZoi.js} +1 -1
  8. package/dist/client/assets/{arc-DTkmmKl3.js → arc-CgL5kFe-.js} +1 -1
  9. package/dist/client/assets/{architectureDiagram-3BPJPVTR-Cw75ay7q.js → architectureDiagram-3BPJPVTR-DxZQWGnx.js} +1 -1
  10. package/dist/client/assets/{astro-DKTNkoRZ.js → astro-DkFc7sbz.js} +1 -1
  11. package/dist/client/assets/{blade-DaM7a9Zp.js → blade-BkY07kcC.js} +1 -1
  12. package/dist/client/assets/{blockDiagram-GPEHLZMM-DAzINMr_.js → blockDiagram-GPEHLZMM-D5a2KZV2.js} +1 -1
  13. package/dist/client/assets/{c-B3C0Or4o.js → c-T1BrPfJ6.js} +1 -1
  14. package/dist/client/assets/{c4Diagram-AAUBKEIU-C7SsS28g.js → c4Diagram-AAUBKEIU-mpMH4kFC.js} +1 -1
  15. package/dist/client/assets/channel-D3niKhl0.js +1 -0
  16. package/dist/client/assets/{chunk-2J33WTMH-DHOUGWx8.js → chunk-2J33WTMH-vMtgRLFH.js} +1 -1
  17. package/dist/client/assets/{chunk-3OPIFGDE-D8d2scLX.js → chunk-3OPIFGDE-Dx-FqyO2.js} +1 -1
  18. package/dist/client/assets/{chunk-4BX2VUAB-BSC-E5yg.js → chunk-4BX2VUAB-CUrPd8Kv.js} +1 -1
  19. package/dist/client/assets/{chunk-55IACEB6-27pC5pKn.js → chunk-55IACEB6-DHg3Nr8A.js} +1 -1
  20. package/dist/client/assets/{chunk-5ZQYHXKU-BM60x82y.js → chunk-5ZQYHXKU-CpDPvbGs.js} +1 -1
  21. package/dist/client/assets/{chunk-727SXJPM-CHCF96vE.js → chunk-727SXJPM-3VOGMxwk.js} +1 -1
  22. package/dist/client/assets/{chunk-AQP2D5EJ-BoVsvmTa.js → chunk-AQP2D5EJ-4dbfbIS6.js} +1 -1
  23. package/dist/client/assets/{chunk-BSJP7CBP-Iip4uSio.js → chunk-BSJP7CBP-Dfyn0Uwp.js} +1 -1
  24. package/dist/client/assets/{chunk-CSCIHK7Q-DuIWPyay.js → chunk-CSCIHK7Q-VTpSKo0F.js} +1 -1
  25. package/dist/client/assets/{chunk-FMBD7UC4-Du6rtd2k.js → chunk-FMBD7UC4-kXD1MyOL.js} +1 -1
  26. package/dist/client/assets/{chunk-KSCS5N6A-BBq105vI.js → chunk-KSCS5N6A-BrVoWOAb.js} +1 -1
  27. package/dist/client/assets/{chunk-L5ZTLDWV-0DmB5Qp8.js → chunk-L5ZTLDWV-wZEQDPsa.js} +1 -1
  28. package/dist/client/assets/{chunk-LZXEDZCA-CoRsjUfr.js → chunk-LZXEDZCA-D3i0B0eg.js} +2 -2
  29. package/dist/client/assets/{chunk-ND2GUHAM-tX8cKEls.js → chunk-ND2GUHAM-hDVHT0bN.js} +1 -1
  30. package/dist/client/assets/{chunk-NZK2D7GU-BoJGgPic.js → chunk-NZK2D7GU-jQUfhp9h.js} +1 -1
  31. package/dist/client/assets/{chunk-O5CBEL6O-mlwCWs97.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-B5efww8M.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-De9QR_Td.js → cobol-8-qBLs-a.js} +1 -1
  38. package/dist/client/assets/{coffee-Ct_GvuHP.js → coffee-Bjz5lkyW.js} +1 -1
  39. package/dist/client/assets/{cose-bilkent-S5V4N54A-ATaJZGF7.js → cose-bilkent-S5V4N54A-BljJ0FSA.js} +1 -1
  40. package/dist/client/assets/{cpp-Dw52w9cj.js → cpp-5BVQCBXT.js} +1 -1
  41. package/dist/client/assets/{crystal-Dx8ADdsd.js → crystal-CCkY93GS.js} +1 -1
  42. package/dist/client/assets/{css-CZ13XvDU.js → css-BTM7Tp2a.js} +1 -1
  43. package/dist/client/assets/{dagre-BM42HDAG-aDltuYut.js → dagre-BM42HDAG-BSynd_2D.js} +1 -1
  44. package/dist/client/assets/{diagram-2AECGRRQ-DGWnHVMJ.js → diagram-2AECGRRQ-K3E2CVdy.js} +1 -1
  45. package/dist/client/assets/{diagram-5GNKFQAL-Dd7eZBKe.js → diagram-5GNKFQAL-BQHIrfKc.js} +1 -1
  46. package/dist/client/assets/{diagram-KO2AKTUF-DWThXREf.js → diagram-KO2AKTUF-Bqs8sNN4.js} +1 -1
  47. package/dist/client/assets/{diagram-LMA3HP47-CXR4Bjtc.js → diagram-LMA3HP47-C9K4bpQe.js} +1 -1
  48. package/dist/client/assets/{diagram-OG6HWLK6-D4Cbf0nW.js → diagram-OG6HWLK6-DK6wIXY2.js} +1 -1
  49. package/dist/client/assets/{dist-CUDhrHNw.js → dist-1nkZYMRy.js} +1 -1
  50. package/dist/client/assets/{edge-CQCjdJKj.js → edge-DqN2FJce.js} +1 -1
  51. package/dist/client/assets/{elixir-bkjwPazA.js → elixir-BiAgRUFF.js} +1 -1
  52. package/dist/client/assets/{elm-CCweX5Cq.js → elm-N1IbY8sz.js} +1 -1
  53. package/dist/client/assets/{erDiagram-TEJ5UH35-BmAyt7SU.js → erDiagram-TEJ5UH35-jsHCiP02.js} +1 -1
  54. package/dist/client/assets/{erb-D-Z-KBLp.js → erb-B-yYlWAZ.js} +1 -1
  55. package/dist/client/assets/{flowDiagram-I6XJVG4X-C6nIFUVc.js → flowDiagram-I6XJVG4X-DOB1dAWG.js} +1 -1
  56. package/dist/client/assets/{ganttDiagram-6RSMTGT7-DMlxThBf.js → ganttDiagram-6RSMTGT7-BYIewcY5.js} +1 -1
  57. package/dist/client/assets/{git-rebase-BdoFdenB.js → git-rebase-CVkPxOAF.js} +1 -1
  58. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-JaIFkAIT.js → gitGraphDiagram-PVQCEYII-VNQzbpv2.js} +1 -1
  59. package/dist/client/assets/{glimmer-js-CZQrBJKq.js → glimmer-js-BmG1xm72.js} +1 -1
  60. package/dist/client/assets/{glimmer-ts-CBYW46D4.js → glimmer-ts-CvTgwZsg.js} +1 -1
  61. package/dist/client/assets/{glsl-wxixKkY_.js → glsl-DwjNNCbW.js} +1 -1
  62. package/dist/client/assets/{graphql-CqZ0Lo5a.js → graphql-BvgkyF8E.js} +1 -1
  63. package/dist/client/assets/{hack-rqWymQRV.js → hack-DH3188x2.js} +1 -1
  64. package/dist/client/assets/{haml-DFw_IoGM.js → haml-B0GTfMhX.js} +1 -1
  65. package/dist/client/assets/{handlebars-3VmTVMYt.js → handlebars-he7hLDd9.js} +1 -1
  66. package/dist/client/assets/{html-C0Li76jB.js → html-DIYgdTBq.js} +1 -1
  67. package/dist/client/assets/{html-derivative-CO-RQW8y.js → html-derivative-2s6MXlci.js} +1 -1
  68. package/dist/client/assets/{http-sPrZOeBY.js → http-COS23XJP.js} +1 -1
  69. package/dist/client/assets/{hurl-DUoPe4Lc.js → hurl-BlZPjeJt.js} +1 -1
  70. package/dist/client/assets/index-BrEVVQOB.js +4021 -0
  71. package/dist/client/assets/index-BsuX6HVI.css +1 -0
  72. package/dist/client/assets/{infoDiagram-5YYISTIA-B6AZ5SCV.js → infoDiagram-5YYISTIA-DQRqk24I.js} +1 -1
  73. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CytMrpo8.js → ishikawaDiagram-YF4QCWOH-DU1rqrLx.js} +1 -1
  74. package/dist/client/assets/{java-Cj0G6QRg.js → java-BAa5w-Qd.js} +1 -1
  75. package/dist/client/assets/{javascript-d5SUuyWD.js → javascript-C9e02ssI.js} +1 -1
  76. package/dist/client/assets/{jinja-BTw9k0vO.js → jinja-Bx37xXwq.js} +1 -1
  77. package/dist/client/assets/{jison-9xSVvR1q.js → jison-m_DEf8Jo.js} +1 -1
  78. package/dist/client/assets/{journeyDiagram-JHISSGLW-Bd4jZUYI.js → journeyDiagram-JHISSGLW-CoHlfevf.js} +1 -1
  79. package/dist/client/assets/{json-DjAt53ka.js → json-DtN5AWRW.js} +1 -1
  80. package/dist/client/assets/{jsx-BX5KmQ7d.js → jsx-BlPpu8bR.js} +1 -1
  81. package/dist/client/assets/{julia-CLLx1dHC.js → julia-BAOmCbHl.js} +1 -1
  82. package/dist/client/assets/{just-C0v80bKe.js → just-C_bvVjwE.js} +1 -1
  83. package/dist/client/assets/{kanban-definition-UN3LZRKU-Ds4pXHJa.js → kanban-definition-UN3LZRKU-BiqYI7_m.js} +1 -1
  84. package/dist/client/assets/{latex-DY-oQfwO.js → latex-81pMfNMt.js} +1 -1
  85. package/dist/client/assets/{line-BbSLfOl6.js → line-DCovs9My.js} +1 -1
  86. package/dist/client/assets/{linear-BMIZJAAR.js → linear-cJF5XHE7.js} +1 -1
  87. package/dist/client/assets/{liquid-DDHDgbZx.js → liquid-sKRTk6dT.js} +1 -1
  88. package/dist/client/assets/{lua-CXymerKS.js → lua-C1uZL4IF.js} +1 -1
  89. package/dist/client/assets/{marko-DoPFsptl.js → marko-BKEzP1CL.js} +1 -1
  90. package/dist/client/assets/{mdc-BxSmTphd.js → mdc-CLkfm94H.js} +1 -1
  91. package/dist/client/assets/{mermaid-parser.core-CcYSvN4q.js → mermaid-parser.core-CTsTbvb2.js} +1 -1
  92. package/dist/client/assets/{mermaid.core-COTNtqgQ.js → mermaid.core-D86HJEwL.js} +3 -3
  93. package/dist/client/assets/{mindmap-definition-RKZ34NQL-BTxraRzn.js → mindmap-definition-RKZ34NQL-CL3heUmL.js} +1 -1
  94. package/dist/client/assets/{nginx-Bma0jNOT.js → nginx-eDGm66pc.js} +1 -1
  95. package/dist/client/assets/{nim-DMBpjygU.js → nim-CoWZPv8-.js} +1 -1
  96. package/dist/client/assets/{perl-CrnrV-AJ.js → perl-MoMqtMVr.js} +1 -1
  97. package/dist/client/assets/{php-CDYxzX6t.js → php-DXXVMAtN.js} +1 -1
  98. package/dist/client/assets/{pieDiagram-4H26LBE5-DglRmzer.js → pieDiagram-4H26LBE5-CWV3TMu4.js} +1 -1
  99. package/dist/client/assets/{pug-DNewy3GU.js → pug-CPWaB94J.js} +1 -1
  100. package/dist/client/assets/{qml-COjcnZ-W.js → qml-lhvpx8vk.js} +1 -1
  101. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-BjSmyES7.js → quadrantDiagram-W4KKPZXB-QV25BYos.js} +1 -1
  102. package/dist/client/assets/{r-CrCaMxLS.js → r-DYbUnmmK.js} +1 -1
  103. package/dist/client/assets/{razor-jeuOZIar.js → razor-DcyOLv96.js} +1 -1
  104. package/dist/client/assets/{regexp-DSHVUX08.js → regexp-BdY10jm0.js} +1 -1
  105. package/dist/client/assets/{requirementDiagram-4Y6WPE33-B4f430jS.js → requirementDiagram-4Y6WPE33-BPMsmU6J.js} +1 -1
  106. package/dist/client/assets/{review-export-Cen1WEcX.js → review-export-CMwjJURs.js} +1 -1
  107. package/dist/client/assets/{rst-CIDgytzc.js → rst-6ShFOzgH.js} +1 -1
  108. package/dist/client/assets/{ruby-DtuseoNq.js → ruby-B04DeVbi.js} +1 -1
  109. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-TQPPlxc6.js → sankeyDiagram-5OEKKPKP-DQJeroPp.js} +1 -1
  110. package/dist/client/assets/{sas-C72Theia.js → sas-Dj26ftNa.js} +1 -1
  111. package/dist/client/assets/{scss-ClECtwRk.js → scss-BOHpBkgl.js} +1 -1
  112. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-D1tx07Wg.js → sequenceDiagram-3UESZ5HK-DdV0Y6Sz.js} +1 -1
  113. package/dist/client/assets/{shellscript-BCwBsi2k.js → shellscript-CpHwjRcU.js} +1 -1
  114. package/dist/client/assets/{shellsession-BrOddEl5.js → shellsession-BJAvf4GN.js} +1 -1
  115. package/dist/client/assets/{soy-Dcs0GWFW.js → soy-B67bZJnL.js} +1 -1
  116. package/dist/client/assets/{sql-BAjA7Gv7.js → sql-8MzOqSsK.js} +1 -1
  117. package/dist/client/assets/{src-CYYhkqTK.js → src-AaoRSmFl.js} +1 -1
  118. package/dist/client/assets/{stata-19ngQtzR.js → stata-aCME945h.js} +1 -1
  119. package/dist/client/assets/{stateDiagram-AJRCARHV-BZRCEzb5.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-Ce2TBRjE.js → surrealql-B_V_HxAi.js} +1 -1
  122. package/dist/client/assets/{svelte-DQ_1eGZz.js → svelte-BcQvTlqz.js} +1 -1
  123. package/dist/client/assets/{templ-Cw2DDxWF.js → templ-DZCQ2blz.js} +1 -1
  124. package/dist/client/assets/{tex-myDSO2eP.js → tex-BfeQ5Wuu.js} +1 -1
  125. package/dist/client/assets/{timeline-definition-PNZ67QCA-CP0OZhBT.js → timeline-definition-PNZ67QCA-CyIS7Zoe.js} +1 -1
  126. package/dist/client/assets/{ts-tags-rh39ZwVs.js → ts-tags-DVWE0E87.js} +1 -1
  127. package/dist/client/assets/{tsx-B0-26jrU.js → tsx-DdJ7Sfqf.js} +1 -1
  128. package/dist/client/assets/{twig-CgasHzPb.js → twig-_gVgaha5.js} +1 -1
  129. package/dist/client/assets/{typescript-Dq3T0c-m.js → typescript-Bj0_LzZV.js} +1 -1
  130. package/dist/client/assets/{vennDiagram-CIIHVFJN-DHaKHj0j.js → vennDiagram-CIIHVFJN-C-J2kWyk.js} +1 -1
  131. package/dist/client/assets/{vue-CzFVh92-.js → vue-Dnt_GBRb.js} +1 -1
  132. package/dist/client/assets/{vue-html-Bv2uFkTH.js → vue-html-ClVA5__5.js} +1 -1
  133. package/dist/client/assets/{vue-vine-DzieBk9Y.js → vue-vine-BCcz4SVP.js} +1 -1
  134. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Dky7jxlZ.js → wardleyDiagram-YWT4CUSO-Dzt4EPh8.js} +1 -1
  135. package/dist/client/assets/{xml-wcdHRHN8.js → xml-BYeUHEti.js} +1 -1
  136. package/dist/client/assets/{xsl-CXrwsLG9.js → xsl-Vsx0SZEV.js} +1 -1
  137. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BQ2hG60h.js → xychartDiagram-2RQKCTM6-BAWZKvwP.js} +1 -1
  138. package/dist/client/assets/{yaml-lO6lK6Xe.js → yaml-C6L1khMK.js} +1 -1
  139. package/dist/client/index.html +2 -2
  140. package/dist/{completions-3UF8uzhx.mjs → completions-DvyV49HY.mjs} +22 -1
  141. package/dist/{doctor-BGYZNIYP.mjs → doctor-Bz9VHuBI.mjs} +7 -6
  142. package/dist/find-tui-binary-DVQADOSF.mjs +101 -0
  143. package/dist/{git-Czo96ymM.mjs → git-BGj31GX-.mjs} +71 -7
  144. package/dist/git-CfDSkUcE.mjs +2 -0
  145. package/dist/{github-DKT0lJXv.mjs → github-DXiEeHzk.mjs} +1 -1
  146. package/dist/{github-CEjtGd41.mjs → github-DpzqNrUh.mjs} +3 -3
  147. package/dist/{github-attachments-Cf17YWp4.mjs → github-attachments-DgOf7BhP.mjs} +2 -2
  148. package/dist/{mcp-Dq7J5QOP.mjs → mcp-zDVzU1vl.mjs} +42 -33
  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/{review-export-BBDWvftT.mjs → review-export-B63eRAVa.mjs} +1 -1
  157. package/dist/{settings-bwe7yQ8U.mjs → search-3R2E5xxr.mjs} +133 -98
  158. package/dist/search-CQ4nsjBX.mjs +2 -0
  159. package/dist/{server-C9i4V36o.mjs → server-Dw3lkQ5q.mjs} +296 -110
  160. package/dist/server-lock-BNI8FKV1.mjs +427 -0
  161. package/dist/session-conflict-Bqt1M4Mp.mjs +96 -0
  162. package/dist/session-manager-BKSZQqDJ.mjs +159 -0
  163. package/dist/session-url-sr7lXXVc.mjs +100 -0
  164. package/dist/tui-search-bridge-BGgLCwMF.mjs +133 -0
  165. package/dist/{update-check-DUuHmPeZ.mjs → update-check-BUfh4Y6c.mjs} +16 -15
  166. package/package.json +9 -4
  167. package/dist/client/assets/channel-lsVHTuYR.js +0 -1
  168. package/dist/client/assets/chunk-QZHKN3VN-AHUiTM0z.js +0 -1
  169. package/dist/client/assets/chunk-WU5MYG2G-D41j4yxb.js +0 -1
  170. package/dist/client/assets/classDiagram-4FO5ZUOK-D1Eo3kly.js +0 -1
  171. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-bAMsbsfB.js +0 -1
  172. package/dist/client/assets/index-B42c0TyV.css +0 -1
  173. package/dist/client/assets/index-BN_-di_r.js +0 -3959
  174. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-Da-mGMA2.js +0 -1
  175. package/dist/find-tui-binary-CRpbYXLC.mjs +0 -52
  176. package/dist/git-DaP_1rVy.mjs +0 -2
  177. package/dist/server-lock-Dd_ss_Il.mjs +0 -153
  178. /package/dist/{apply-suggestion-DNNsC5gx.mjs → apply-suggestion-CHYnw68I.mjs} +0 -0
  179. /package/dist/{comment-format-B5AcGcR-.mjs → comment-format-B85NHZnG.mjs} +0 -0
  180. /package/dist/{diff-fingerprint-C8YO3TTE.mjs → diff-fingerprint-BgR0tu1o.mjs} +0 -0
  181. /package/dist/{handoff-DPoIyeWn.mjs → handoff-LAFtmnHf.mjs} +0 -0
  182. /package/dist/{plan-format-BQyx--mp.mjs → plan-format-BwJh5JSE.mjs} +0 -0
@@ -0,0 +1,100 @@
1
+ import { g as SESSION_TOKEN_QUERY, x as isLoopbackHost } from "./server-lock-BNI8FKV1.mjs";
2
+ import { randomUUID } from "node:crypto";
3
+ import { join } from "node:path";
4
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ //#region src/lib/json-atomic.ts
7
+ /** Write JSON via a temp file and rename so readers never see a partial file. */
8
+ function writeJsonAtomically(path, value) {
9
+ mkdirSync(join(path, ".."), { recursive: true });
10
+ const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
11
+ writeFileSync(temporary, JSON.stringify(value, null, 2), "utf-8");
12
+ renameSync(temporary, path);
13
+ }
14
+ //#endregion
15
+ //#region src/lib/settings.ts
16
+ const SETTINGS_FILE = join(join(homedir(), ".config", "diffing"), "settings.json");
17
+ const DEFAULTS = {
18
+ defaultMode: "web",
19
+ staged: true,
20
+ untracked: true,
21
+ diffStyle: "split",
22
+ defaultTabSize: 4,
23
+ theme: "rose-pine",
24
+ editorIDE: "default",
25
+ lineDiffType: "word",
26
+ lineWrap: false,
27
+ diffIndicators: "classic",
28
+ showLineNumbers: true,
29
+ hunkSeparators: "line-info",
30
+ lineHoverHighlight: "both",
31
+ fontSize: 13,
32
+ expandContextByDefault: false,
33
+ collapsedContextThreshold: 10,
34
+ expansionLineCount: 20,
35
+ haptics: true,
36
+ sounds: true,
37
+ uiFont: null,
38
+ monoFont: null,
39
+ density: "comfortable",
40
+ autoCollapseLineThreshold: 400,
41
+ requireViewAllBeforeSend: false,
42
+ showStatusBar: true,
43
+ savedReplies: [],
44
+ ignoreSpaceChange: false,
45
+ ignoreAllSpace: false
46
+ };
47
+ function loadSettings() {
48
+ try {
49
+ const data = readFileSync(SETTINGS_FILE, "utf-8");
50
+ const settings = {
51
+ ...DEFAULTS,
52
+ ...JSON.parse(data)
53
+ };
54
+ if (settings.defaultMode !== "web" && settings.defaultMode !== "tui") settings.defaultMode = DEFAULTS.defaultMode;
55
+ return settings;
56
+ } catch {
57
+ return { ...DEFAULTS };
58
+ }
59
+ }
60
+ function saveSettings(settings) {
61
+ const merged = {
62
+ ...loadSettings(),
63
+ ...settings
64
+ };
65
+ writeJsonAtomically(SETTINGS_FILE, merged);
66
+ return merged;
67
+ }
68
+ //#endregion
69
+ //#region src/lib/session-url.ts
70
+ /** Loopback-safe review URL for web / gh-pr locks; null for TUI or invalid ports. */
71
+ function reviewSessionBaseUrl(lock) {
72
+ if ((lock.mode ?? "web") === "tui" || !(lock.port > 0)) return null;
73
+ if (!isLoopbackHost(lock.host) && lock.host !== "0.0.0.0" && lock.host !== "::") return null;
74
+ const host = lock.host === "0.0.0.0" || lock.host === "::" ? "127.0.0.1" : lock.host;
75
+ const path = lock.mode === "gh-pr" ? "/gh/pr" : "";
76
+ return `http://${host}:${lock.port}${path}`;
77
+ }
78
+ /** Browseable review URL without auth query params (auth uses cookie + header). */
79
+ function appendSessionToken(url, _token) {
80
+ try {
81
+ const parsed = new URL(url);
82
+ parsed.searchParams.delete(SESSION_TOKEN_QUERY);
83
+ const search = parsed.searchParams.toString();
84
+ return `${parsed.origin}${parsed.pathname}${search ? `?${search}` : ""}${parsed.hash}`;
85
+ } catch {
86
+ return url;
87
+ }
88
+ }
89
+ /** Public review URL for humans (no `?token=` — session cookie is set when HTML is served). */
90
+ function reviewSessionUrl(lock) {
91
+ const base = reviewSessionBaseUrl(lock);
92
+ if (!base) return null;
93
+ return base;
94
+ }
95
+ /** Join an API path to a session base URL (origin only; strips any legacy `?token=`). */
96
+ function joinSessionApiUrl(base, path) {
97
+ return `${new URL(base).origin}${path.startsWith("/") ? path : `/${path}`}`;
98
+ }
99
+ //#endregion
100
+ export { loadSettings as a, reviewSessionUrl as i, joinSessionApiUrl as n, saveSettings as o, reviewSessionBaseUrl as r, appendSessionToken as t };
@@ -0,0 +1,133 @@
1
+ import { s as getFileContent } from "./git-BGj31GX-.mjs";
2
+ import { randomUUID } from "node:crypto";
3
+ import { createServer } from "node:http";
4
+ //#region src/lib/tui-search-bridge.ts
5
+ const MAX_REQUEST_BYTES = 8 * 1024 * 1024;
6
+ const MAX_PREVIEW_BYTES = 2 * 1024 * 1024;
7
+ function sendJson(response, status, value) {
8
+ const body = JSON.stringify(value);
9
+ response.writeHead(status, {
10
+ "content-type": "application/json; charset=utf-8",
11
+ "content-length": Buffer.byteLength(body),
12
+ connection: "close"
13
+ });
14
+ response.end(body);
15
+ }
16
+ async function readJson(request) {
17
+ const chunks = [];
18
+ let size = 0;
19
+ for await (const chunk of request) {
20
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
21
+ size += buffer.length;
22
+ if (size > MAX_REQUEST_BYTES) throw new Error("request body is too large");
23
+ chunks.push(buffer);
24
+ }
25
+ if (chunks.length === 0) return {};
26
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
27
+ }
28
+ async function runSearch(body) {
29
+ const { searchAll, searchContent, searchFiles, searchSymbols } = await import("./search-CQ4nsjBX.mjs");
30
+ const scope = body.scope ?? "all";
31
+ const query = typeof body.query === "string" ? body.query : "";
32
+ const limit = typeof body.limit === "number" ? body.limit : void 0;
33
+ const paths = Array.isArray(body.changedPaths) ? body.changedPaths.filter((path) => typeof path === "string") : void 0;
34
+ if (scope === "text") return searchContent(query, {
35
+ limit,
36
+ regex: !!body.regex,
37
+ paths
38
+ });
39
+ if (scope === "symbols") return searchSymbols(query, {
40
+ limit,
41
+ paths
42
+ });
43
+ if (scope === "files") return searchFiles(query, {
44
+ limit,
45
+ paths
46
+ });
47
+ return searchAll(query, {
48
+ limit,
49
+ regex: !!body.regex,
50
+ paths
51
+ });
52
+ }
53
+ function loadTuiPreview(body) {
54
+ if (typeof body.path !== "string" || !body.path) throw new Error("preview path is required");
55
+ const buffer = getFileContent(body.path, "new");
56
+ if (!buffer) return {
57
+ path: body.path,
58
+ content: "",
59
+ missing: true,
60
+ binary: false,
61
+ truncated: false
62
+ };
63
+ if (buffer.subarray(0, Math.min(buffer.length, 8192)).includes(0)) return {
64
+ path: body.path,
65
+ content: "",
66
+ missing: false,
67
+ binary: true,
68
+ truncated: false
69
+ };
70
+ const truncated = buffer.length > MAX_PREVIEW_BYTES;
71
+ return {
72
+ path: body.path,
73
+ content: buffer.subarray(0, MAX_PREVIEW_BYTES).toString("utf8"),
74
+ missing: false,
75
+ binary: false,
76
+ truncated
77
+ };
78
+ }
79
+ /**
80
+ * Exposes the web UI's long-lived fff search engine to the native TUI without
81
+ * duplicating its native binding or its frecency database. The bridge is
82
+ * loopback-only and protected by a per-process capability.
83
+ */
84
+ async function startTuiSearchBridge() {
85
+ const capability = randomUUID();
86
+ const server = createServer(async (request, response) => {
87
+ if (request.headers["x-diffing-capability"] !== capability) {
88
+ sendJson(response, 401, { error: "invalid TUI search capability" });
89
+ return;
90
+ }
91
+ try {
92
+ if (request.method === "POST" && request.url === "/search") {
93
+ sendJson(response, 200, await runSearch(await readJson(request)));
94
+ return;
95
+ }
96
+ if (request.method === "POST" && request.url === "/preview") {
97
+ sendJson(response, 200, loadTuiPreview(await readJson(request)));
98
+ return;
99
+ }
100
+ if (request.method === "POST" && request.url === "/track") {
101
+ const body = await readJson(request);
102
+ if (typeof body.path === "string") {
103
+ const { trackSelection } = await import("./search-CQ4nsjBX.mjs");
104
+ await trackSelection(typeof body.query === "string" ? body.query : "", body.path);
105
+ }
106
+ sendJson(response, 200, { ok: true });
107
+ return;
108
+ }
109
+ sendJson(response, 404, { error: "not found" });
110
+ } catch (error) {
111
+ sendJson(response, 500, { error: error?.message ?? "TUI search failed" });
112
+ }
113
+ });
114
+ await new Promise((resolveP, reject) => {
115
+ server.once("error", reject);
116
+ server.listen(0, "127.0.0.1", () => {
117
+ server.off("error", reject);
118
+ resolveP();
119
+ });
120
+ });
121
+ const address = server.address();
122
+ if (!address || typeof address === "string") {
123
+ server.close();
124
+ throw new Error("could not resolve TUI search bridge address");
125
+ }
126
+ return {
127
+ endpoint: `http://127.0.0.1:${address.port}`,
128
+ capability,
129
+ close: () => new Promise((resolveP) => server.close(() => resolveP()))
130
+ };
131
+ }
132
+ //#endregion
133
+ export { startTuiSearchBridge };
@@ -32,15 +32,18 @@ async function checkForUpdates(currentVersion) {
32
32
  try {
33
33
  const controller = new AbortController();
34
34
  const id = setTimeout(() => controller.abort(), 1e3);
35
- const res = await fetch("https://registry.npmjs.org/diffing/latest", { signal: controller.signal });
36
- clearTimeout(id);
37
- if (!res.ok) return null;
38
- const data = await res.json();
39
- if (!data.version) return null;
40
- return {
41
- hasUpdate: isNewerVersion(currentVersion, data.version),
42
- latestVersion: data.version
43
- };
35
+ try {
36
+ const res = await fetch("https://registry.npmjs.org/diffing/latest", { signal: controller.signal });
37
+ if (!res.ok) return null;
38
+ const data = await res.json();
39
+ if (!data.version) return null;
40
+ return {
41
+ hasUpdate: isNewerVersion(currentVersion, data.version),
42
+ latestVersion: data.version
43
+ };
44
+ } finally {
45
+ clearTimeout(id);
46
+ }
44
47
  } catch {
45
48
  return null;
46
49
  }
@@ -106,10 +109,7 @@ async function runUpdateCommand() {
106
109
  } catch {}
107
110
  console.log(`Running: ${cmd} ${args.join(" ")}\n`);
108
111
  const exitCode = await new Promise((res) => {
109
- const child = spawn(cmd, args, {
110
- stdio: "inherit",
111
- shell: true
112
- });
112
+ const child = spawn(cmd, args, { stdio: "inherit" });
113
113
  child.on("close", (code) => {
114
114
  res(code ?? 0);
115
115
  });
@@ -120,8 +120,9 @@ async function runUpdateCommand() {
120
120
  });
121
121
  if (exitCode === 0) console.log(`\n\x1b[38;5;82mSuccessfully updated diffing to v${latest}!\x1b[0m\n`);
122
122
  else {
123
- console.error(`\n\x1b[38;5;196mFailed to update diffing. Please try running the command manually with sudo if required:\x1b[0m`);
124
- console.error(` sudo ${cmd} ${args.join(" ")}\n`);
123
+ console.error(`\n\x1b[38;5;196mFailed to update diffing. Install into your user prefix instead of using sudo:\x1b[0m`);
124
+ console.error(` npm config get prefix # e.g. ~/.npm-global or ~/.local`);
125
+ console.error(` ${cmd} ${args.join(" ")}\n`);
125
126
  }
126
127
  return exitCode;
127
128
  }
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "diffing",
3
- "version": "0.10.5",
3
+ "version": "0.12.0",
4
4
  "description": "local-first CLI for reviewing, navigating, and discussing git diffs with AI",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
7
10
  "packageManager": "pnpm@11.6.0",
8
11
  "homepage": "https://github.com/ahmedragab20/diffing",
9
12
  "repository": {
@@ -26,10 +29,11 @@
26
29
  "dist"
27
30
  ],
28
31
  "scripts": {
29
- "build": "tsdown && vite build && pnpm run build:tui",
32
+ "build": "pnpm run build:ts && pnpm run build:tui && pnpm run bundle:tui",
30
33
  "build:ts": "tsdown && vite build",
31
34
  "build:tui": "cargo build --release --manifest-path crates/diffing-tui/Cargo.toml",
32
35
  "build:tui:debug": "cargo build --manifest-path crates/diffing-tui/Cargo.toml",
36
+ "bundle:tui": "node scripts/stage-tui-binary.mjs",
33
37
  "changeset": "changeset",
34
38
  "dev:client": "vite",
35
39
  "dev:server": "tsx src/cli.ts --no-open --port 3433",
@@ -38,8 +42,9 @@
38
42
  "test:ts": "vitest run",
39
43
  "test:tui": "cargo test --manifest-path crates/diffing-tui/Cargo.toml",
40
44
  "test:watch": "vitest",
41
- "prepublishOnly": "pnpm run build",
42
- "release": "pnpm run build && changeset publish",
45
+ "verify:tui-bundle": "vitest run src/__tests__/native-bundle.test.ts src/__tests__/find-tui-binary.test.ts",
46
+ "verify:release-bundle": "node scripts/verify-tui-bundle.mjs",
47
+ "prepublishOnly": "pnpm run verify:release-bundle",
43
48
  "version-packages": "changeset version"
44
49
  },
45
50
  "dependencies": {
@@ -1 +0,0 @@
1
- import{at as e,ot as t}from"./chunk-CSCIHK7Q-DuIWPyay.js";var n=(n,r)=>t.lang.round(e.parse(n)[r]);export{n as t};
@@ -1 +0,0 @@
1
- import{h as e}from"./src-CYYhkqTK.js";var t=class{constructor(e){this.init=e,this.records=this.init()}static{e(this,`ImperativeState`)}reset(){this.records=this.init()}};export{t};
@@ -1 +0,0 @@
1
- import{h as e,p as t}from"./src-CYYhkqTK.js";import{x as n}from"./chunk-CSCIHK7Q-DuIWPyay.js";var r=e(e=>{let{securityLevel:r}=n(),i=t(`body`);return r===`sandbox`&&(i=t((t(`#i${e}`).node()?.contentDocument??document).body)),i.select(`#${e}`)},`selectSvgElement`);export{r as t};
@@ -1 +0,0 @@
1
- import{h as e}from"./src-CYYhkqTK.js";import"./chunk-CSCIHK7Q-DuIWPyay.js";import"./chunk-5ZQYHXKU-BM60x82y.js";import"./chunk-O5CBEL6O-mlwCWs97.js";import"./chunk-FMBD7UC4-Du6rtd2k.js";import"./chunk-BSJP7CBP-Iip4uSio.js";import"./chunk-L5ZTLDWV-0DmB5Qp8.js";import"./chunk-ND2GUHAM-tX8cKEls.js";import"./chunk-55IACEB6-27pC5pKn.js";import"./chunk-2J33WTMH-DHOUGWx8.js";import"./chunk-NZK2D7GU-BoJGgPic.js";import"./chunk-3OPIFGDE-D8d2scLX.js";import"./chunk-KSCS5N6A-BBq105vI.js";import"./chunk-LZXEDZCA-CoRsjUfr.js";import{i as t,n,r,t as i}from"./chunk-727SXJPM-CHCF96vE.js";var a={parser:n,get db(){return new i},renderer:r,styles:t,init:e(e=>{e.class||={},e.class.arrowMarkerAbsolute=e.arrowMarkerAbsolute},`init`)};export{a as diagram};
@@ -1 +0,0 @@
1
- import{h as e}from"./src-CYYhkqTK.js";import"./chunk-CSCIHK7Q-DuIWPyay.js";import"./chunk-5ZQYHXKU-BM60x82y.js";import"./chunk-O5CBEL6O-mlwCWs97.js";import"./chunk-FMBD7UC4-Du6rtd2k.js";import"./chunk-BSJP7CBP-Iip4uSio.js";import"./chunk-L5ZTLDWV-0DmB5Qp8.js";import"./chunk-ND2GUHAM-tX8cKEls.js";import"./chunk-55IACEB6-27pC5pKn.js";import"./chunk-2J33WTMH-DHOUGWx8.js";import"./chunk-NZK2D7GU-BoJGgPic.js";import"./chunk-3OPIFGDE-D8d2scLX.js";import"./chunk-KSCS5N6A-BBq105vI.js";import"./chunk-LZXEDZCA-CoRsjUfr.js";import{i as t,n,r,t as i}from"./chunk-727SXJPM-CHCF96vE.js";var a={parser:n,get db(){return new i},renderer:r,styles:t,init:e(e=>{e.class||={},e.class.arrowMarkerAbsolute=e.arrowMarkerAbsolute},`init`)};export{a as diagram};