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.
- package/README.md +76 -41
- package/dist/{cli-agent-BJiATn11.mjs → cli-agent-CWsOHN-j.mjs} +198 -57
- package/dist/{cli-gh-_bkDCxhh.mjs → cli-gh-DI69gJGo.mjs} +27 -17
- package/dist/cli.mjs +189 -229
- package/dist/client/assets/{angular-html-CBcwKYDC.js → angular-html-PLPuQo0k.js} +1 -1
- package/dist/client/assets/{angular-ts-DRBYUaJA.js → angular-ts-CE02Ij4b.js} +1 -1
- package/dist/client/assets/{apl-BM0X8jeL.js → apl-CsuUKZoi.js} +1 -1
- package/dist/client/assets/{arc-DTkmmKl3.js → arc-CgL5kFe-.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-Cw75ay7q.js → architectureDiagram-3BPJPVTR-DxZQWGnx.js} +1 -1
- package/dist/client/assets/{astro-DKTNkoRZ.js → astro-DkFc7sbz.js} +1 -1
- package/dist/client/assets/{blade-DaM7a9Zp.js → blade-BkY07kcC.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-DAzINMr_.js → blockDiagram-GPEHLZMM-D5a2KZV2.js} +1 -1
- package/dist/client/assets/{c-B3C0Or4o.js → c-T1BrPfJ6.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-C7SsS28g.js → c4Diagram-AAUBKEIU-mpMH4kFC.js} +1 -1
- package/dist/client/assets/channel-D3niKhl0.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-DHOUGWx8.js → chunk-2J33WTMH-vMtgRLFH.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-D8d2scLX.js → chunk-3OPIFGDE-Dx-FqyO2.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-BSC-E5yg.js → chunk-4BX2VUAB-CUrPd8Kv.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-27pC5pKn.js → chunk-55IACEB6-DHg3Nr8A.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-BM60x82y.js → chunk-5ZQYHXKU-CpDPvbGs.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-CHCF96vE.js → chunk-727SXJPM-3VOGMxwk.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-BoVsvmTa.js → chunk-AQP2D5EJ-4dbfbIS6.js} +1 -1
- package/dist/client/assets/{chunk-BSJP7CBP-Iip4uSio.js → chunk-BSJP7CBP-Dfyn0Uwp.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-DuIWPyay.js → chunk-CSCIHK7Q-VTpSKo0F.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-Du6rtd2k.js → chunk-FMBD7UC4-kXD1MyOL.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-BBq105vI.js → chunk-KSCS5N6A-BrVoWOAb.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-0DmB5Qp8.js → chunk-L5ZTLDWV-wZEQDPsa.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-CoRsjUfr.js → chunk-LZXEDZCA-D3i0B0eg.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-tX8cKEls.js → chunk-ND2GUHAM-hDVHT0bN.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-BoJGgPic.js → chunk-NZK2D7GU-jQUfhp9h.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-mlwCWs97.js → chunk-O5CBEL6O-CX_vPWhk.js} +1 -1
- package/dist/client/assets/chunk-QZHKN3VN-CZLFuGpt.js +1 -0
- package/dist/client/assets/chunk-WU5MYG2G-BhcpjkaB.js +1 -0
- package/dist/client/assets/{chunk-XPW4576I-B5efww8M.js → chunk-XPW4576I-Co_-vDB4.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DK5KJNIt.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-y5K9t6Se.js +1 -0
- package/dist/client/assets/{cobol-De9QR_Td.js → cobol-8-qBLs-a.js} +1 -1
- package/dist/client/assets/{coffee-Ct_GvuHP.js → coffee-Bjz5lkyW.js} +1 -1
- package/dist/client/assets/{cose-bilkent-S5V4N54A-ATaJZGF7.js → cose-bilkent-S5V4N54A-BljJ0FSA.js} +1 -1
- package/dist/client/assets/{cpp-Dw52w9cj.js → cpp-5BVQCBXT.js} +1 -1
- package/dist/client/assets/{crystal-Dx8ADdsd.js → crystal-CCkY93GS.js} +1 -1
- package/dist/client/assets/{css-CZ13XvDU.js → css-BTM7Tp2a.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-aDltuYut.js → dagre-BM42HDAG-BSynd_2D.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-DGWnHVMJ.js → diagram-2AECGRRQ-K3E2CVdy.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-Dd7eZBKe.js → diagram-5GNKFQAL-BQHIrfKc.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-DWThXREf.js → diagram-KO2AKTUF-Bqs8sNN4.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-CXR4Bjtc.js → diagram-LMA3HP47-C9K4bpQe.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-D4Cbf0nW.js → diagram-OG6HWLK6-DK6wIXY2.js} +1 -1
- package/dist/client/assets/{dist-CUDhrHNw.js → dist-1nkZYMRy.js} +1 -1
- package/dist/client/assets/{edge-CQCjdJKj.js → edge-DqN2FJce.js} +1 -1
- package/dist/client/assets/{elixir-bkjwPazA.js → elixir-BiAgRUFF.js} +1 -1
- package/dist/client/assets/{elm-CCweX5Cq.js → elm-N1IbY8sz.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-BmAyt7SU.js → erDiagram-TEJ5UH35-jsHCiP02.js} +1 -1
- package/dist/client/assets/{erb-D-Z-KBLp.js → erb-B-yYlWAZ.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-C6nIFUVc.js → flowDiagram-I6XJVG4X-DOB1dAWG.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-DMlxThBf.js → ganttDiagram-6RSMTGT7-BYIewcY5.js} +1 -1
- package/dist/client/assets/{git-rebase-BdoFdenB.js → git-rebase-CVkPxOAF.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-JaIFkAIT.js → gitGraphDiagram-PVQCEYII-VNQzbpv2.js} +1 -1
- package/dist/client/assets/{glimmer-js-CZQrBJKq.js → glimmer-js-BmG1xm72.js} +1 -1
- package/dist/client/assets/{glimmer-ts-CBYW46D4.js → glimmer-ts-CvTgwZsg.js} +1 -1
- package/dist/client/assets/{glsl-wxixKkY_.js → glsl-DwjNNCbW.js} +1 -1
- package/dist/client/assets/{graphql-CqZ0Lo5a.js → graphql-BvgkyF8E.js} +1 -1
- package/dist/client/assets/{hack-rqWymQRV.js → hack-DH3188x2.js} +1 -1
- package/dist/client/assets/{haml-DFw_IoGM.js → haml-B0GTfMhX.js} +1 -1
- package/dist/client/assets/{handlebars-3VmTVMYt.js → handlebars-he7hLDd9.js} +1 -1
- package/dist/client/assets/{html-C0Li76jB.js → html-DIYgdTBq.js} +1 -1
- package/dist/client/assets/{html-derivative-CO-RQW8y.js → html-derivative-2s6MXlci.js} +1 -1
- package/dist/client/assets/{http-sPrZOeBY.js → http-COS23XJP.js} +1 -1
- package/dist/client/assets/{hurl-DUoPe4Lc.js → hurl-BlZPjeJt.js} +1 -1
- package/dist/client/assets/index-BrEVVQOB.js +4021 -0
- package/dist/client/assets/index-BsuX6HVI.css +1 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-B6AZ5SCV.js → infoDiagram-5YYISTIA-DQRqk24I.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CytMrpo8.js → ishikawaDiagram-YF4QCWOH-DU1rqrLx.js} +1 -1
- package/dist/client/assets/{java-Cj0G6QRg.js → java-BAa5w-Qd.js} +1 -1
- package/dist/client/assets/{javascript-d5SUuyWD.js → javascript-C9e02ssI.js} +1 -1
- package/dist/client/assets/{jinja-BTw9k0vO.js → jinja-Bx37xXwq.js} +1 -1
- package/dist/client/assets/{jison-9xSVvR1q.js → jison-m_DEf8Jo.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-Bd4jZUYI.js → journeyDiagram-JHISSGLW-CoHlfevf.js} +1 -1
- package/dist/client/assets/{json-DjAt53ka.js → json-DtN5AWRW.js} +1 -1
- package/dist/client/assets/{jsx-BX5KmQ7d.js → jsx-BlPpu8bR.js} +1 -1
- package/dist/client/assets/{julia-CLLx1dHC.js → julia-BAOmCbHl.js} +1 -1
- package/dist/client/assets/{just-C0v80bKe.js → just-C_bvVjwE.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-Ds4pXHJa.js → kanban-definition-UN3LZRKU-BiqYI7_m.js} +1 -1
- package/dist/client/assets/{latex-DY-oQfwO.js → latex-81pMfNMt.js} +1 -1
- package/dist/client/assets/{line-BbSLfOl6.js → line-DCovs9My.js} +1 -1
- package/dist/client/assets/{linear-BMIZJAAR.js → linear-cJF5XHE7.js} +1 -1
- package/dist/client/assets/{liquid-DDHDgbZx.js → liquid-sKRTk6dT.js} +1 -1
- package/dist/client/assets/{lua-CXymerKS.js → lua-C1uZL4IF.js} +1 -1
- package/dist/client/assets/{marko-DoPFsptl.js → marko-BKEzP1CL.js} +1 -1
- package/dist/client/assets/{mdc-BxSmTphd.js → mdc-CLkfm94H.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-CcYSvN4q.js → mermaid-parser.core-CTsTbvb2.js} +1 -1
- package/dist/client/assets/{mermaid.core-COTNtqgQ.js → mermaid.core-D86HJEwL.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-BTxraRzn.js → mindmap-definition-RKZ34NQL-CL3heUmL.js} +1 -1
- package/dist/client/assets/{nginx-Bma0jNOT.js → nginx-eDGm66pc.js} +1 -1
- package/dist/client/assets/{nim-DMBpjygU.js → nim-CoWZPv8-.js} +1 -1
- package/dist/client/assets/{perl-CrnrV-AJ.js → perl-MoMqtMVr.js} +1 -1
- package/dist/client/assets/{php-CDYxzX6t.js → php-DXXVMAtN.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-DglRmzer.js → pieDiagram-4H26LBE5-CWV3TMu4.js} +1 -1
- package/dist/client/assets/{pug-DNewy3GU.js → pug-CPWaB94J.js} +1 -1
- package/dist/client/assets/{qml-COjcnZ-W.js → qml-lhvpx8vk.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-BjSmyES7.js → quadrantDiagram-W4KKPZXB-QV25BYos.js} +1 -1
- package/dist/client/assets/{r-CrCaMxLS.js → r-DYbUnmmK.js} +1 -1
- package/dist/client/assets/{razor-jeuOZIar.js → razor-DcyOLv96.js} +1 -1
- package/dist/client/assets/{regexp-DSHVUX08.js → regexp-BdY10jm0.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-B4f430jS.js → requirementDiagram-4Y6WPE33-BPMsmU6J.js} +1 -1
- package/dist/client/assets/{review-export-Cen1WEcX.js → review-export-CMwjJURs.js} +1 -1
- package/dist/client/assets/{rst-CIDgytzc.js → rst-6ShFOzgH.js} +1 -1
- package/dist/client/assets/{ruby-DtuseoNq.js → ruby-B04DeVbi.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-TQPPlxc6.js → sankeyDiagram-5OEKKPKP-DQJeroPp.js} +1 -1
- package/dist/client/assets/{sas-C72Theia.js → sas-Dj26ftNa.js} +1 -1
- package/dist/client/assets/{scss-ClECtwRk.js → scss-BOHpBkgl.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-D1tx07Wg.js → sequenceDiagram-3UESZ5HK-DdV0Y6Sz.js} +1 -1
- package/dist/client/assets/{shellscript-BCwBsi2k.js → shellscript-CpHwjRcU.js} +1 -1
- package/dist/client/assets/{shellsession-BrOddEl5.js → shellsession-BJAvf4GN.js} +1 -1
- package/dist/client/assets/{soy-Dcs0GWFW.js → soy-B67bZJnL.js} +1 -1
- package/dist/client/assets/{sql-BAjA7Gv7.js → sql-8MzOqSsK.js} +1 -1
- package/dist/client/assets/{src-CYYhkqTK.js → src-AaoRSmFl.js} +1 -1
- package/dist/client/assets/{stata-19ngQtzR.js → stata-aCME945h.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-BZRCEzb5.js → stateDiagram-AJRCARHV-CMD_Xj2M.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-vLl7D4ue.js +1 -0
- package/dist/client/assets/{surrealql-Ce2TBRjE.js → surrealql-B_V_HxAi.js} +1 -1
- package/dist/client/assets/{svelte-DQ_1eGZz.js → svelte-BcQvTlqz.js} +1 -1
- package/dist/client/assets/{templ-Cw2DDxWF.js → templ-DZCQ2blz.js} +1 -1
- package/dist/client/assets/{tex-myDSO2eP.js → tex-BfeQ5Wuu.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-CP0OZhBT.js → timeline-definition-PNZ67QCA-CyIS7Zoe.js} +1 -1
- package/dist/client/assets/{ts-tags-rh39ZwVs.js → ts-tags-DVWE0E87.js} +1 -1
- package/dist/client/assets/{tsx-B0-26jrU.js → tsx-DdJ7Sfqf.js} +1 -1
- package/dist/client/assets/{twig-CgasHzPb.js → twig-_gVgaha5.js} +1 -1
- package/dist/client/assets/{typescript-Dq3T0c-m.js → typescript-Bj0_LzZV.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-DHaKHj0j.js → vennDiagram-CIIHVFJN-C-J2kWyk.js} +1 -1
- package/dist/client/assets/{vue-CzFVh92-.js → vue-Dnt_GBRb.js} +1 -1
- package/dist/client/assets/{vue-html-Bv2uFkTH.js → vue-html-ClVA5__5.js} +1 -1
- package/dist/client/assets/{vue-vine-DzieBk9Y.js → vue-vine-BCcz4SVP.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Dky7jxlZ.js → wardleyDiagram-YWT4CUSO-Dzt4EPh8.js} +1 -1
- package/dist/client/assets/{xml-wcdHRHN8.js → xml-BYeUHEti.js} +1 -1
- package/dist/client/assets/{xsl-CXrwsLG9.js → xsl-Vsx0SZEV.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-BQ2hG60h.js → xychartDiagram-2RQKCTM6-BAWZKvwP.js} +1 -1
- package/dist/client/assets/{yaml-lO6lK6Xe.js → yaml-C6L1khMK.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/{completions-3UF8uzhx.mjs → completions-DvyV49HY.mjs} +22 -1
- package/dist/{doctor-BGYZNIYP.mjs → doctor-Bz9VHuBI.mjs} +7 -6
- package/dist/find-tui-binary-DVQADOSF.mjs +101 -0
- package/dist/{git-Czo96ymM.mjs → git-BGj31GX-.mjs} +71 -7
- package/dist/git-CfDSkUcE.mjs +2 -0
- package/dist/{github-DKT0lJXv.mjs → github-DXiEeHzk.mjs} +1 -1
- package/dist/{github-CEjtGd41.mjs → github-DpzqNrUh.mjs} +3 -3
- package/dist/{github-attachments-Cf17YWp4.mjs → github-attachments-DgOf7BhP.mjs} +2 -2
- package/dist/{mcp-Dq7J5QOP.mjs → mcp-zDVzU1vl.mjs} +42 -33
- package/dist/native/tui-darwin-arm64/diffing-tui +0 -0
- package/dist/native/tui-darwin-x64/diffing-tui +0 -0
- package/dist/native/tui-linux-arm64-gnu/diffing-tui +0 -0
- package/dist/native/tui-linux-arm64-musl/diffing-tui +0 -0
- package/dist/native/tui-linux-x64-gnu/diffing-tui +0 -0
- package/dist/native/tui-linux-x64-musl/diffing-tui +0 -0
- package/dist/native/tui-win32-x64-msvc/diffing-tui.exe +0 -0
- package/dist/{review-export-BBDWvftT.mjs → review-export-B63eRAVa.mjs} +1 -1
- package/dist/{settings-bwe7yQ8U.mjs → search-3R2E5xxr.mjs} +133 -98
- package/dist/search-CQ4nsjBX.mjs +2 -0
- package/dist/{server-C9i4V36o.mjs → server-Dw3lkQ5q.mjs} +296 -110
- package/dist/server-lock-BNI8FKV1.mjs +427 -0
- package/dist/session-conflict-Bqt1M4Mp.mjs +96 -0
- package/dist/session-manager-BKSZQqDJ.mjs +159 -0
- package/dist/session-url-sr7lXXVc.mjs +100 -0
- package/dist/tui-search-bridge-BGgLCwMF.mjs +133 -0
- package/dist/{update-check-DUuHmPeZ.mjs → update-check-BUfh4Y6c.mjs} +16 -15
- package/package.json +9 -4
- package/dist/client/assets/channel-lsVHTuYR.js +0 -1
- package/dist/client/assets/chunk-QZHKN3VN-AHUiTM0z.js +0 -1
- package/dist/client/assets/chunk-WU5MYG2G-D41j4yxb.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-D1Eo3kly.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-bAMsbsfB.js +0 -1
- package/dist/client/assets/index-B42c0TyV.css +0 -1
- package/dist/client/assets/index-BN_-di_r.js +0 -3959
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-Da-mGMA2.js +0 -1
- package/dist/find-tui-binary-CRpbYXLC.mjs +0 -52
- package/dist/git-DaP_1rVy.mjs +0 -2
- package/dist/server-lock-Dd_ss_Il.mjs +0 -153
- /package/dist/{apply-suggestion-DNNsC5gx.mjs → apply-suggestion-CHYnw68I.mjs} +0 -0
- /package/dist/{comment-format-B5AcGcR-.mjs → comment-format-B85NHZnG.mjs} +0 -0
- /package/dist/{diff-fingerprint-C8YO3TTE.mjs → diff-fingerprint-BgR0tu1o.mjs} +0 -0
- /package/dist/{handoff-DPoIyeWn.mjs → handoff-LAFtmnHf.mjs} +0 -0
- /package/dist/{plan-format-BQyx--mp.mjs → plan-format-BwJh5JSE.mjs} +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import { a as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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
|
+
import { t as formatComments } from "./comment-format-B85NHZnG.mjs";
|
|
5
|
+
import { n as formatPlanReview, r as sectionTitleForLine, t as extractPlanLines } from "./plan-format-BwJh5JSE.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";
|
|
6
8
|
import { execFileSync } from "node:child_process";
|
|
7
9
|
import { createHash } from "node:crypto";
|
|
8
10
|
import { fileURLToPath } from "node:url";
|
|
@@ -34,6 +36,7 @@ const DEFAULTS = {
|
|
|
34
36
|
pickaxeAll: false,
|
|
35
37
|
exitCode: false,
|
|
36
38
|
quiet: false,
|
|
39
|
+
suppressPatch: false,
|
|
37
40
|
noPrefix: false,
|
|
38
41
|
binary: false,
|
|
39
42
|
fullIndex: false,
|
|
@@ -51,6 +54,7 @@ const DEFAULTS = {
|
|
|
51
54
|
outputMode: "auto",
|
|
52
55
|
host: "127.0.0.1",
|
|
53
56
|
noOpen: false,
|
|
57
|
+
insecureNoAuth: false,
|
|
54
58
|
reuseSession: false,
|
|
55
59
|
replaceSession: false,
|
|
56
60
|
help: false,
|
|
@@ -58,6 +62,7 @@ const DEFAULTS = {
|
|
|
58
62
|
includeUnstaged: true,
|
|
59
63
|
includeUntracked: true,
|
|
60
64
|
tui: false,
|
|
65
|
+
viewOnly: false,
|
|
61
66
|
gpu: false,
|
|
62
67
|
showMode: false,
|
|
63
68
|
showRevspecs: []
|
|
@@ -181,6 +186,10 @@ const DIFFING_OPTIONS = {
|
|
|
181
186
|
type: "boolean",
|
|
182
187
|
default: false
|
|
183
188
|
},
|
|
189
|
+
"insecure-no-auth": {
|
|
190
|
+
type: "boolean",
|
|
191
|
+
default: false
|
|
192
|
+
},
|
|
184
193
|
"reuse-session": {
|
|
185
194
|
type: "boolean",
|
|
186
195
|
default: false
|
|
@@ -201,6 +210,10 @@ const DIFFING_OPTIONS = {
|
|
|
201
210
|
type: "boolean",
|
|
202
211
|
default: false
|
|
203
212
|
},
|
|
213
|
+
view: {
|
|
214
|
+
type: "boolean",
|
|
215
|
+
default: false
|
|
216
|
+
},
|
|
204
217
|
gpu: {
|
|
205
218
|
type: "boolean",
|
|
206
219
|
default: false
|
|
@@ -226,6 +239,7 @@ function printHelp() {
|
|
|
226
239
|
|
|
227
240
|
Usage: diffing [<git diff options>] [<revision>...] [-- <path>...]
|
|
228
241
|
diffing --web [<git diff options>] [<revision>...] [-- <path>...]
|
|
242
|
+
diffing view [<git diff options>] [<revision>...] [-- <path>...]
|
|
229
243
|
diffing [server options]
|
|
230
244
|
|
|
231
245
|
Git Diff Options (drop-in replacement for git diff):`);
|
|
@@ -233,26 +247,33 @@ Git Diff Options (drop-in replacement for git diff):`);
|
|
|
233
247
|
console.log(`
|
|
234
248
|
Diffing Server Options:
|
|
235
249
|
--port <port> Port to run the server on (default: random available port)
|
|
236
|
-
--host <host> Host address to bind to (default: 127.0.0.1).
|
|
237
|
-
|
|
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.
|
|
238
256
|
--no-open Don't open the browser automatically
|
|
239
|
-
--reuse-session
|
|
240
|
-
--replace-session
|
|
257
|
+
--reuse-session Open the active review instead of starting another
|
|
258
|
+
--replace-session Stop the active review and start a replacement
|
|
241
259
|
--gh-pr <ref> Open a GitHub PR review session (number, owner/repo#N, or URL)
|
|
242
260
|
Same as: diffing "gh pr <ref>"
|
|
243
261
|
|
|
244
262
|
Output Modes:
|
|
245
263
|
By default diffing auto-selects the best output mode:
|
|
246
264
|
- Terminal mode: when output is a pipe, redirect, or non-TTY
|
|
247
|
-
- Web
|
|
265
|
+
- Web or TUI: saved preference for an interactive terminal (web by default)
|
|
248
266
|
|
|
249
|
-
Force a mode with --web, --terminal, or --
|
|
267
|
+
Force a mode with --web, --terminal, --tui, or --view flags.
|
|
268
|
+
Change the interactive default with: diffing mode <web|tui>
|
|
269
|
+
--view opens a focused, read-only diff browser with fff-powered search.
|
|
250
270
|
--tui is experimental and opt-in. It opens a native-Rust terminal
|
|
251
271
|
interface that mirrors the web dashboard. Falls back to git diff
|
|
252
272
|
output if the environment cannot support a TUI (piped stdin, CI,
|
|
253
273
|
missing binary).
|
|
254
274
|
|
|
255
275
|
Subcommands:
|
|
276
|
+
view [diff options] Browse diffs in the focused read-only native TUI
|
|
256
277
|
show <revspec>... Drop-in for 'git show'. Renders commit metadata
|
|
257
278
|
above the diff. Accepts commits, ranges, tags.
|
|
258
279
|
await-review Block until human clicks Send to agent; print XML
|
|
@@ -262,11 +283,13 @@ Subcommands:
|
|
|
262
283
|
comment edit|delete <id>
|
|
263
284
|
progress --message … Live agent progress toast
|
|
264
285
|
url Print the active review base URL
|
|
286
|
+
sessions List, select, open, and stop running review sessions
|
|
265
287
|
plan <submit|await|list|show|versions|reply|resolve>
|
|
266
288
|
gh <status|overview|threads|reviews|pr-fetch|pr-list-comments|pr-review>
|
|
267
289
|
mcp [--repo PATH] Stdio MCP server for agents
|
|
268
290
|
inspect <summary|files|hunks|slice|search>
|
|
269
291
|
Bounded reads from a running web, TUI, or PR session
|
|
292
|
+
mode [web|tui] Get or set the default interactive review mode
|
|
270
293
|
doctor Environment self-check
|
|
271
294
|
completion <bash|zsh|fish>
|
|
272
295
|
update Check for a newer npm release
|
|
@@ -275,7 +298,7 @@ Custom ranges (e.g. main..feature) and 'gh pr' sessions also display a
|
|
|
275
298
|
"what is this diff" banner in the web UI summarising the diff source.
|
|
276
299
|
|
|
277
300
|
Examples:
|
|
278
|
-
diffing Review uncommitted changes (
|
|
301
|
+
diffing Review uncommitted changes (preferred UI)
|
|
279
302
|
diffing --staged Review staged changes
|
|
280
303
|
diffing HEAD~3 Review last 3 commits
|
|
281
304
|
diffing main..feature Compare branches
|
|
@@ -287,8 +310,13 @@ Examples:
|
|
|
287
310
|
diffing -U10 Diff with 10 context lines
|
|
288
311
|
diffing --word-diff=color Word-level diff in color
|
|
289
312
|
diffing -b -w Ignore whitespace changes
|
|
290
|
-
diffing --host 0.0.0.0
|
|
313
|
+
diffing --host 0.0.0.0 --insecure-no-auth
|
|
314
|
+
Expose the review UI on the LAN without API tokens
|
|
315
|
+
diffing view Browse the working-tree diff in the TUI
|
|
316
|
+
diffing view --staged Browse staged changes
|
|
317
|
+
diffing --view main..feature Browse a branch comparison
|
|
291
318
|
diffing --tui Open the experimental TUI (native Rust)
|
|
319
|
+
diffing mode tui Use the TUI by default in interactive terminals
|
|
292
320
|
diffing await-review Agent: wait for human handoff
|
|
293
321
|
diffing plan submit PLAN.md Agent: submit a plan for approval
|
|
294
322
|
diffing mcp --repo /abs/path MCP server bound to one repository
|
|
@@ -437,6 +465,15 @@ function preprocessOptionalValueArgs(rawArgs) {
|
|
|
437
465
|
"find-renames",
|
|
438
466
|
"break-rewrites"
|
|
439
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
|
+
]);
|
|
440
477
|
const startsWithDigit = (s) => typeof s === "string" && /^[0-9]/.test(s);
|
|
441
478
|
const out = [];
|
|
442
479
|
for (let i = 0; i < rawArgs.length; i++) {
|
|
@@ -465,6 +502,13 @@ function preprocessOptionalValueArgs(rawArgs) {
|
|
|
465
502
|
}
|
|
466
503
|
continue;
|
|
467
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
|
+
}
|
|
468
512
|
out.push(arg);
|
|
469
513
|
}
|
|
470
514
|
return out;
|
|
@@ -479,7 +523,7 @@ function preprocessOptionalValueArgs(rawArgs) {
|
|
|
479
523
|
* 3. Parse known flags via node:util.parseArgs
|
|
480
524
|
* 4. Anything unknown / positional becomes a revision or pathspec
|
|
481
525
|
*/
|
|
482
|
-
function parseDiffOptions(rawArgs) {
|
|
526
|
+
function parseDiffOptions(rawArgs, defaultInteractiveMode = "web") {
|
|
483
527
|
const { values, positionals } = parseArgs({
|
|
484
528
|
options: {
|
|
485
529
|
...GIT_DIFF_OPTIONS,
|
|
@@ -500,9 +544,11 @@ function parseDiffOptions(rawArgs) {
|
|
|
500
544
|
if (values.port) opts.port = parseInt(values.port, 10);
|
|
501
545
|
if (values.host) opts.host = values.host;
|
|
502
546
|
if (values["no-open"]) opts.noOpen = true;
|
|
547
|
+
if (values["insecure-no-auth"]) opts.insecureNoAuth = true;
|
|
503
548
|
if (values["reuse-session"]) opts.reuseSession = true;
|
|
504
549
|
if (values["replace-session"]) opts.replaceSession = true;
|
|
505
550
|
if (values["gh-pr"]) opts.ghPr = String(values["gh-pr"]);
|
|
551
|
+
if (values.view) opts.viewOnly = true;
|
|
506
552
|
if (values.staged || values.cached) opts.staged = true;
|
|
507
553
|
if (values.merge) opts.merge = true;
|
|
508
554
|
const algo = values["diff-algorithm"];
|
|
@@ -576,7 +622,11 @@ function parseDiffOptions(rawArgs) {
|
|
|
576
622
|
if (values.raw) opts.outputFormat = "raw";
|
|
577
623
|
if (values.numstat) opts.outputFormat = "numstat";
|
|
578
624
|
if (values.shortstat) opts.outputFormat = "shortstat";
|
|
579
|
-
if (values.stat !== void 0)
|
|
625
|
+
if (values.stat !== void 0) {
|
|
626
|
+
opts.outputFormat = "stat";
|
|
627
|
+
const statVal = values.stat;
|
|
628
|
+
if (statVal) opts.statParam = statVal;
|
|
629
|
+
}
|
|
580
630
|
if (values.summary) opts.outputFormat = "summary";
|
|
581
631
|
if (values["name-only"]) opts.outputFormat = "name-only";
|
|
582
632
|
if (values["name-status"]) opts.outputFormat = "name-status";
|
|
@@ -586,8 +636,14 @@ function parseDiffOptions(rawArgs) {
|
|
|
586
636
|
if (values.dirstat) opts.dirstat = values.dirstat;
|
|
587
637
|
if (values["dirstat-by-file"]) opts.dirstatByFile = values["dirstat-by-file"];
|
|
588
638
|
if (values.cumulative) opts.cumulative = true;
|
|
589
|
-
if (values["no-patch"])
|
|
590
|
-
|
|
639
|
+
if (values["no-patch"]) {
|
|
640
|
+
opts.outputFormat = void 0;
|
|
641
|
+
opts.suppressPatch = true;
|
|
642
|
+
}
|
|
643
|
+
if (values.check) {
|
|
644
|
+
opts.outputFormat = void 0;
|
|
645
|
+
opts.check = true;
|
|
646
|
+
}
|
|
591
647
|
if (values["diff-filter"]) opts.diffFilter = values["diff-filter"];
|
|
592
648
|
if (values.S) opts.pickaxeString = values.S;
|
|
593
649
|
if (values.G) opts.pickaxeRegex = values.G;
|
|
@@ -630,18 +686,17 @@ function parseDiffOptions(rawArgs) {
|
|
|
630
686
|
}
|
|
631
687
|
const dashDashIdx = rawArgs.indexOf("--");
|
|
632
688
|
if (dashDashIdx >= 0) {
|
|
633
|
-
for (let i = 0; i < dashDashIdx; i++) {
|
|
634
|
-
const arg = rawArgs[i];
|
|
635
|
-
if (!arg.startsWith("-")) opts.revisions.push(arg);
|
|
636
|
-
}
|
|
637
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);
|
|
638
692
|
} else for (const p of positionals) opts.revisions.push(p);
|
|
639
|
-
if (values.
|
|
693
|
+
if (values.view) opts.outputMode = "tui";
|
|
694
|
+
else if (values.tui) opts.outputMode = "tui";
|
|
640
695
|
else if (values.web) opts.outputMode = "web";
|
|
641
696
|
else if (values.terminal) opts.outputMode = "terminal";
|
|
642
|
-
if (process.stdout.isTTY && opts.outputMode === "auto") opts.outputMode = "web";
|
|
697
|
+
if (process.stdout.isTTY && opts.outputMode === "auto") opts.outputMode = values["gh-pr"] ? "web" : defaultInteractiveMode;
|
|
643
698
|
else if (!process.stdout.isTTY && opts.outputMode === "auto") opts.outputMode = "terminal";
|
|
644
|
-
if (opts.outputFormat || opts.patchWithRaw || opts.patchWithStat || opts.exitCode || opts.quiet || opts.outputFile) opts.outputMode = "terminal";
|
|
699
|
+
if (opts.outputFormat || opts.patchWithRaw || opts.patchWithStat || opts.compactSummary || opts.dirstat || opts.dirstatByFile || opts.cumulative || opts.suppressPatch || opts.check || opts.exitCode || opts.quiet || opts.outputFile || opts.colorMoved || opts.colorMovedWs || opts.srcPrefix || opts.dstPrefix || opts.noPrefix || opts.linePrefix || opts.submodule !== void 0 && opts.submodule !== "diff" || opts.extDiff) opts.outputMode = "terminal";
|
|
645
700
|
return opts;
|
|
646
701
|
}
|
|
647
702
|
/**
|
|
@@ -682,7 +737,7 @@ function buildGitDiffArgs(opts) {
|
|
|
682
737
|
if (opts.outputFormat === "raw") args.push("--raw");
|
|
683
738
|
if (opts.outputFormat === "numstat") args.push("--numstat");
|
|
684
739
|
if (opts.outputFormat === "shortstat") args.push("--shortstat");
|
|
685
|
-
if (opts.outputFormat === "stat") args.push("--stat");
|
|
740
|
+
if (opts.outputFormat === "stat") args.push(opts.statParam ? `--stat=${opts.statParam}` : "--stat");
|
|
686
741
|
if (opts.outputFormat === "summary") args.push("--summary");
|
|
687
742
|
if (opts.outputFormat === "name-only") args.push("--name-only");
|
|
688
743
|
if (opts.outputFormat === "name-status") args.push("--name-status");
|
|
@@ -693,6 +748,7 @@ function buildGitDiffArgs(opts) {
|
|
|
693
748
|
if (opts.dirstatByFile) args.push(`--dirstat-by-file=${opts.dirstatByFile}`);
|
|
694
749
|
if (opts.cumulative) args.push("--cumulative");
|
|
695
750
|
if (opts.check) args.push("--check");
|
|
751
|
+
if (opts.suppressPatch) args.push("--no-patch");
|
|
696
752
|
if (opts.diffFilter) args.push(`--diff-filter=${opts.diffFilter}`);
|
|
697
753
|
if (opts.pickaxeString) args.push(`-S${opts.pickaxeString}`);
|
|
698
754
|
if (opts.pickaxeRegex) args.push(`-G${opts.pickaxeRegex}`);
|
|
@@ -723,6 +779,23 @@ function buildGitDiffArgs(opts) {
|
|
|
723
779
|
return args;
|
|
724
780
|
}
|
|
725
781
|
/**
|
|
782
|
+
* Build the machine-stable patch arguments consumed by the native index.
|
|
783
|
+
* Presentation-only word/color modes are implemented by the renderer and
|
|
784
|
+
* must not rewrite the unified patch stream that Rust parses.
|
|
785
|
+
*/
|
|
786
|
+
function buildTuiGitDiffArgs(opts) {
|
|
787
|
+
return buildGitDiffArgs({
|
|
788
|
+
...opts,
|
|
789
|
+
revisions: opts.showMode ? [...opts.showRevspecs] : [...opts.revisions],
|
|
790
|
+
pathspecs: [...opts.pathspecs],
|
|
791
|
+
wordDiff: void 0,
|
|
792
|
+
wordDiffRegex: void 0,
|
|
793
|
+
colorWords: void 0,
|
|
794
|
+
colorMoved: void 0,
|
|
795
|
+
colorMovedWs: void 0
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
726
799
|
* Transform a `parseDiffOptions(...)` result into a "show mode" variant:
|
|
727
800
|
* moves any parsed revisions into `showRevspecs`, clears `revisions` (so the
|
|
728
801
|
* existing diff-engine path does not try to `git diff` them), and sets the
|
|
@@ -738,6 +811,88 @@ function intoShowMode(opts) {
|
|
|
738
811
|
return opts;
|
|
739
812
|
}
|
|
740
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
|
|
741
896
|
//#region src/lib/diff-overview.ts
|
|
742
897
|
/**
|
|
743
898
|
* Compose the working-tree banner. Used by the default `git diff` (unstaged +
|
|
@@ -930,7 +1085,6 @@ function summariseCommitSeries(series, rows) {
|
|
|
930
1085
|
}
|
|
931
1086
|
//#endregion
|
|
932
1087
|
//#region src/lib/diff-engine.ts
|
|
933
|
-
const MAX_BUFFER = 50 * 1024 * 1024;
|
|
934
1088
|
/**
|
|
935
1089
|
* Determine whether to use the "standard" web mode (unstaged+staged+untracked)
|
|
936
1090
|
* or a "custom" mode (specific revisions / pathspecs).
|
|
@@ -945,8 +1099,8 @@ function isCustomMode$1(opts) {
|
|
|
945
1099
|
function parseFilePaths(patch) {
|
|
946
1100
|
const paths = /* @__PURE__ */ new Set();
|
|
947
1101
|
for (const line of patch.split("\n")) {
|
|
948
|
-
const
|
|
949
|
-
if (
|
|
1102
|
+
const parsed = parseGitDiffHeaderPaths(line);
|
|
1103
|
+
if (parsed) paths.add(parsed[1]);
|
|
950
1104
|
}
|
|
951
1105
|
return [...paths];
|
|
952
1106
|
}
|
|
@@ -958,9 +1112,9 @@ function parseBinaryFiles(patch, untrackedFiles) {
|
|
|
958
1112
|
if (!line.startsWith("Binary files ") || !line.includes(" differ")) continue;
|
|
959
1113
|
let filePath = "";
|
|
960
1114
|
for (let j = i - 1; j >= 0; j--) {
|
|
961
|
-
const
|
|
962
|
-
if (
|
|
963
|
-
filePath =
|
|
1115
|
+
const parsed = parseGitDiffHeaderPaths(lines[j]);
|
|
1116
|
+
if (parsed) {
|
|
1117
|
+
filePath = parsed[1];
|
|
964
1118
|
break;
|
|
965
1119
|
}
|
|
966
1120
|
}
|
|
@@ -1025,12 +1179,10 @@ async function executeDiffAsync(opts) {
|
|
|
1025
1179
|
*/
|
|
1026
1180
|
async function executeDiffWithMeta(opts) {
|
|
1027
1181
|
const { patch, commits, truncated } = await executeDiffAsync(opts);
|
|
1028
|
-
const repoName =
|
|
1029
|
-
const branch = getBranchName();
|
|
1030
|
-
const untrackedFiles = opts.includeUntracked && !opts.showMode ? await getUntrackedFilePathsAsync() : [];
|
|
1182
|
+
const [{ repoName, branch }, untrackedFiles] = await Promise.all([getRepoMetadataAsync(), opts.includeUntracked && !opts.showMode ? getUntrackedFilePathsAsync() : Promise.resolve([])]);
|
|
1031
1183
|
const binaryFiles = parseBinaryFiles(patch, new Set(untrackedFiles));
|
|
1032
1184
|
const filePaths = parseFilePaths(patch);
|
|
1033
|
-
const tabSizeMap =
|
|
1185
|
+
const tabSizeMap = await getTabSizeForFilesAsync(filePaths);
|
|
1034
1186
|
let overview;
|
|
1035
1187
|
if (opts.showMode && commits && commits.length > 0) overview = buildCommitOverview({
|
|
1036
1188
|
commits: commits.map((c) => ({
|
|
@@ -1107,11 +1259,7 @@ function runTerminalDiff(opts) {
|
|
|
1107
1259
|
}
|
|
1108
1260
|
finalArgs.push(...args);
|
|
1109
1261
|
try {
|
|
1110
|
-
execFileSync("git", ["diff", ...finalArgs], {
|
|
1111
|
-
encoding: "utf-8",
|
|
1112
|
-
maxBuffer: MAX_BUFFER,
|
|
1113
|
-
stdio: "inherit"
|
|
1114
|
-
});
|
|
1262
|
+
execFileSync("git", ["diff", ...finalArgs], { stdio: "inherit" });
|
|
1115
1263
|
return 0;
|
|
1116
1264
|
} catch (err) {
|
|
1117
1265
|
if (err.status === 1 && opts.exitCode) return 1;
|
|
@@ -1132,11 +1280,7 @@ function runTerminalShow(opts) {
|
|
|
1132
1280
|
];
|
|
1133
1281
|
if (opts.pathspecs.length > 0) args.push("--", ...opts.pathspecs);
|
|
1134
1282
|
try {
|
|
1135
|
-
execFileSync("git", args, {
|
|
1136
|
-
encoding: "utf-8",
|
|
1137
|
-
maxBuffer: MAX_BUFFER,
|
|
1138
|
-
stdio: "inherit"
|
|
1139
|
-
});
|
|
1283
|
+
execFileSync("git", args, { stdio: "inherit" });
|
|
1140
1284
|
return 0;
|
|
1141
1285
|
} catch (err) {
|
|
1142
1286
|
return err.status ?? 1;
|
|
@@ -1155,6 +1299,7 @@ function validateEnvironment() {
|
|
|
1155
1299
|
var FileCommentStore = class {
|
|
1156
1300
|
dirPath;
|
|
1157
1301
|
filePath;
|
|
1302
|
+
mutationQueue = Promise.resolve();
|
|
1158
1303
|
/**
|
|
1159
1304
|
* @param storageDir Absolute directory to persist `comments.json` in.
|
|
1160
1305
|
* Defaults to the per-repo storage dir under `~/.diffing` — comments are
|
|
@@ -1186,74 +1331,100 @@ var FileCommentStore = class {
|
|
|
1186
1331
|
console.error("Failed to save comments to file:", err);
|
|
1187
1332
|
}
|
|
1188
1333
|
}
|
|
1334
|
+
/** Serialize each read-modify-write cycle so concurrent API calls cannot overwrite one another. */
|
|
1335
|
+
enqueueMutation(operation) {
|
|
1336
|
+
const result = this.mutationQueue.then(operation, operation);
|
|
1337
|
+
this.mutationQueue = result.then(() => void 0, () => void 0);
|
|
1338
|
+
return result;
|
|
1339
|
+
}
|
|
1189
1340
|
async add(comment) {
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1341
|
+
return this.enqueueMutation(async () => {
|
|
1342
|
+
const comments = await this.getAll();
|
|
1343
|
+
comments.push(comment);
|
|
1344
|
+
await this.save(comments);
|
|
1345
|
+
return comment;
|
|
1346
|
+
});
|
|
1194
1347
|
}
|
|
1195
1348
|
async update(id, fields) {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1349
|
+
return this.enqueueMutation(async () => {
|
|
1350
|
+
const comments = await this.getAll();
|
|
1351
|
+
const index = comments.findIndex((c) => c.id === id);
|
|
1352
|
+
if (index === -1) return null;
|
|
1353
|
+
const comment = comments[index];
|
|
1354
|
+
if (fields.body !== void 0) comment.body = fields.body;
|
|
1355
|
+
if (fields.status !== void 0) comment.status = fields.status;
|
|
1356
|
+
await this.save(comments);
|
|
1357
|
+
return comment;
|
|
1358
|
+
});
|
|
1204
1359
|
}
|
|
1205
1360
|
async resolveAllOpen() {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
c.status
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1361
|
+
return this.enqueueMutation(async () => {
|
|
1362
|
+
const comments = await this.getAll();
|
|
1363
|
+
let n = 0;
|
|
1364
|
+
for (const c of comments) if (c.status === "open") {
|
|
1365
|
+
c.status = "resolved";
|
|
1366
|
+
n++;
|
|
1367
|
+
}
|
|
1368
|
+
if (n > 0) await this.save(comments);
|
|
1369
|
+
return n;
|
|
1370
|
+
});
|
|
1214
1371
|
}
|
|
1215
1372
|
async remove(id) {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1373
|
+
return this.enqueueMutation(async () => {
|
|
1374
|
+
const comments = await this.getAll();
|
|
1375
|
+
const index = comments.findIndex((c) => c.id === id);
|
|
1376
|
+
if (index === -1) return false;
|
|
1377
|
+
comments.splice(index, 1);
|
|
1378
|
+
await this.save(comments);
|
|
1379
|
+
return true;
|
|
1380
|
+
});
|
|
1222
1381
|
}
|
|
1223
1382
|
async addReply(commentId, reply) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1383
|
+
return this.enqueueMutation(async () => {
|
|
1384
|
+
const comments = await this.getAll();
|
|
1385
|
+
const index = comments.findIndex((c) => c.id === commentId);
|
|
1386
|
+
if (index === -1) return null;
|
|
1387
|
+
const comment = comments[index];
|
|
1388
|
+
if (!comment.replies) comment.replies = [];
|
|
1389
|
+
comment.replies.push(reply);
|
|
1390
|
+
await this.save(comments);
|
|
1391
|
+
return comment;
|
|
1392
|
+
});
|
|
1232
1393
|
}
|
|
1233
1394
|
async removeReply(commentId, replyId) {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1395
|
+
return this.enqueueMutation(async () => {
|
|
1396
|
+
const comments = await this.getAll();
|
|
1397
|
+
const index = comments.findIndex((c) => c.id === commentId);
|
|
1398
|
+
if (index === -1) return null;
|
|
1399
|
+
const comment = comments[index];
|
|
1400
|
+
const replyIndex = comment.replies.findIndex((r) => r.id === replyId);
|
|
1401
|
+
if (replyIndex === -1) return null;
|
|
1402
|
+
comment.replies.splice(replyIndex, 1);
|
|
1403
|
+
await this.save(comments);
|
|
1404
|
+
return comment;
|
|
1405
|
+
});
|
|
1243
1406
|
}
|
|
1244
1407
|
async updateReply(commentId, replyId, body) {
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1408
|
+
return this.enqueueMutation(async () => {
|
|
1409
|
+
const comments = await this.getAll();
|
|
1410
|
+
const index = comments.findIndex((c) => c.id === commentId);
|
|
1411
|
+
if (index === -1) return null;
|
|
1412
|
+
const comment = comments[index];
|
|
1413
|
+
const reply = comment.replies.find((r) => r.id === replyId);
|
|
1414
|
+
if (!reply) return null;
|
|
1415
|
+
reply.body = body;
|
|
1416
|
+
await this.save(comments);
|
|
1417
|
+
return comment;
|
|
1418
|
+
});
|
|
1254
1419
|
}
|
|
1255
1420
|
};
|
|
1256
1421
|
//#endregion
|
|
1422
|
+
//#region src/lib/types.ts
|
|
1423
|
+
/** Runtime guard for comment data crossing HTTP or persisted-storage boundaries. */
|
|
1424
|
+
function isReviewCommentSide(value) {
|
|
1425
|
+
return value === "deletions" || value === "additions";
|
|
1426
|
+
}
|
|
1427
|
+
//#endregion
|
|
1257
1428
|
//#region src/lib/plans.ts
|
|
1258
1429
|
/** Absolute path of the persisted markdown mirror for a plan id. */
|
|
1259
1430
|
function planSourceFilePath(storageDir, planId) {
|
|
@@ -1613,7 +1784,7 @@ function guiEditorCommand(bin, absolutePath, platform) {
|
|
|
1613
1784
|
function terminalEditorCommand(bin, absolutePath, platform, env) {
|
|
1614
1785
|
if (platform === "darwin") return {
|
|
1615
1786
|
cmd: "osascript",
|
|
1616
|
-
args: ["-e", `tell application "Terminal" to do script "${bin}
|
|
1787
|
+
args: ["-e", `tell application "Terminal" to do script ("${bin} " & quoted form of "${absolutePath.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}")`]
|
|
1617
1788
|
};
|
|
1618
1789
|
if (platform === "win32") return {
|
|
1619
1790
|
cmd: "cmd.exe",
|
|
@@ -2765,8 +2936,13 @@ function collectPrAvatarUrls(session) {
|
|
|
2765
2936
|
function isCustomMode(opts) {
|
|
2766
2937
|
return opts.revisions.length > 0 || opts.pathspecs.length > 0 || opts.showMode;
|
|
2767
2938
|
}
|
|
2768
|
-
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
|
+
}) {
|
|
2769
2944
|
const app = new Hono();
|
|
2945
|
+
app.use("*", createServerAuthMiddleware(security));
|
|
2770
2946
|
let diffOpts = { ...diffOptsInput };
|
|
2771
2947
|
const customMode = isCustomMode(diffOpts);
|
|
2772
2948
|
const store = commentStore ?? new FileCommentStore();
|
|
@@ -3347,6 +3523,7 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
|
|
|
3347
3523
|
});
|
|
3348
3524
|
app.post("/api/comments", async (c) => {
|
|
3349
3525
|
const body = await c.req.json();
|
|
3526
|
+
if (!isReviewCommentSide(body.side)) return c.json({ error: "side must be additions or deletions" }, 400);
|
|
3350
3527
|
const severityRaw = body.severity;
|
|
3351
3528
|
const severity = severityRaw === "blocking" || severityRaw === "nit" || severityRaw === "question" || severityRaw === "praise" || severityRaw === "none" ? severityRaw : void 0;
|
|
3352
3529
|
const comment = {
|
|
@@ -3415,7 +3592,7 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
|
|
|
3415
3592
|
if (!relPath) return c.json({ error: "Forbidden file path" }, 403);
|
|
3416
3593
|
const absolutePath = resolve(root, relPath);
|
|
3417
3594
|
const content = await readFile(absolutePath, "utf-8");
|
|
3418
|
-
const { applySuggestionToContent } = await import("./apply-suggestion-
|
|
3595
|
+
const { applySuggestionToContent } = await import("./apply-suggestion-CHYnw68I.mjs");
|
|
3419
3596
|
const result = applySuggestionToContent({
|
|
3420
3597
|
content,
|
|
3421
3598
|
lineNumber: comment.lineNumber,
|
|
@@ -3662,7 +3839,7 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
|
|
|
3662
3839
|
const session = await prStore.get();
|
|
3663
3840
|
if (!session) return notInPrMode(c);
|
|
3664
3841
|
try {
|
|
3665
|
-
const { fetchPrChecks } = await import("./github-
|
|
3842
|
+
const { fetchPrChecks } = await import("./github-DXiEeHzk.mjs");
|
|
3666
3843
|
const checks = await fetchPrChecks(resolvedFromSession(session), session.headSha);
|
|
3667
3844
|
const summary = {
|
|
3668
3845
|
total: checks.length,
|
|
@@ -3694,7 +3871,7 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
|
|
|
3694
3871
|
const text = typeof body.body === "string" ? body.body.trim() : "";
|
|
3695
3872
|
if (!text) return c.json({ error: "body is required" }, 400);
|
|
3696
3873
|
try {
|
|
3697
|
-
const { replyToPrComment } = await import("./github-
|
|
3874
|
+
const { replyToPrComment } = await import("./github-DXiEeHzk.mjs");
|
|
3698
3875
|
const result = await replyToPrComment({
|
|
3699
3876
|
resolved: resolvedFromSession(session),
|
|
3700
3877
|
inReplyTo: id,
|
|
@@ -3908,8 +4085,8 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
|
|
|
3908
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);
|
|
3909
4086
|
const generalBody = typeof body.body === "string" ? body.body : "";
|
|
3910
4087
|
if (body.dryRun === true) {
|
|
3911
|
-
const { buildReviewPayload, resolvedFromSession } = await import("./github-
|
|
3912
|
-
const { rewriteLocalAttachmentsInBodies } = await import("./github-attachments-
|
|
4088
|
+
const { buildReviewPayload, resolvedFromSession } = await import("./github-DXiEeHzk.mjs");
|
|
4089
|
+
const { rewriteLocalAttachmentsInBodies } = await import("./github-attachments-DgOf7BhP.mjs");
|
|
3913
4090
|
const resolved = resolvedFromSession(session);
|
|
3914
4091
|
const comments = session.comments ?? [];
|
|
3915
4092
|
const rewritten = await rewriteLocalAttachmentsInBodies(resolved, [generalBody, ...comments.map((c) => c.body ?? "")], { dryRun: true });
|
|
@@ -4006,7 +4183,7 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
|
|
|
4006
4183
|
const openCount = all.filter((x) => x.status === "open").length;
|
|
4007
4184
|
let diffFingerprints;
|
|
4008
4185
|
try {
|
|
4009
|
-
const { fingerprintDiffFiles } = await import("./diff-fingerprint-
|
|
4186
|
+
const { fingerprintDiffFiles } = await import("./diff-fingerprint-BgR0tu1o.mjs");
|
|
4010
4187
|
if (prMode) {
|
|
4011
4188
|
const prSession = await prStore.get();
|
|
4012
4189
|
if (prSession?.diff) diffFingerprints = fingerprintDiffFiles(prSession.diff);
|
|
@@ -4074,7 +4251,7 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
|
|
|
4074
4251
|
} catch (err) {
|
|
4075
4252
|
return c.json({ error: err?.message ?? "Failed to compute current diff" }, 500);
|
|
4076
4253
|
}
|
|
4077
|
-
const { fingerprintDiffFiles, diffSinceLast, filesToReviewSinceLast } = await import("./diff-fingerprint-
|
|
4254
|
+
const { fingerprintDiffFiles, diffSinceLast, filesToReviewSinceLast } = await import("./diff-fingerprint-BgR0tu1o.mjs");
|
|
4078
4255
|
const delta = diffSinceLast(previous, fingerprintDiffFiles(currentPatch));
|
|
4079
4256
|
return c.json({
|
|
4080
4257
|
hasBaseline: true,
|
|
@@ -4299,10 +4476,19 @@ function createApp(clientDir, diffOptsInput = DEFAULTS, commentStore, planStore,
|
|
|
4299
4476
|
try {
|
|
4300
4477
|
const content = await readFile(fullPath);
|
|
4301
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
|
+
}
|
|
4302
4486
|
return new Response(content, { headers: { "Content-Type": contentType } });
|
|
4303
4487
|
} catch {
|
|
4304
|
-
const
|
|
4305
|
-
|
|
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 });
|
|
4306
4492
|
}
|
|
4307
4493
|
});
|
|
4308
4494
|
return app;
|
|
@@ -4393,7 +4579,7 @@ async function startServer(options) {
|
|
|
4393
4579
|
throw new Error(`Failed to build PR session for ${options.prRef}: ${detail}`);
|
|
4394
4580
|
}
|
|
4395
4581
|
}
|
|
4396
|
-
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);
|
|
4397
4583
|
return new Promise((resolve) => {
|
|
4398
4584
|
serve({
|
|
4399
4585
|
fetch: app.fetch,
|
|
@@ -4408,4 +4594,4 @@ async function startServer(options) {
|
|
|
4408
4594
|
});
|
|
4409
4595
|
}
|
|
4410
4596
|
//#endregion
|
|
4411
|
-
export {
|
|
4597
|
+
export { buildTuiGitDiffArgs as a, printHelp as c, buildGitDiffArgs as i, runTerminalDiff as n, intoShowMode as o, validateEnvironment as r, parseDiffOptions as s, startServer as t };
|