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
package/README.md CHANGED
@@ -110,7 +110,7 @@ Blazing-fast, native fuzzy code search integrated directly into the sidebar sear
110
110
 
111
111
  - **Fuzzy File Search** (`Files` scope) — Error-tolerant fuzzy matching on workspace paths using a native Rust engine.
112
112
  - **Codebase Grep** (`Text` scope) — Instant case-insensitive text search with full **Regular Expression** support.
113
- - **Syntactic Symbol Search** (`Symbols` scope) — Finds function declarations, class headers, type definitions, and variable assignments across JavaScript, TypeScript, Go, Rust, and Python (17+ language patterns).
113
+ - **Syntactic Symbol Search** (`Symbols` scope) — Finds function declarations, class headers, type definitions, and variable assignments across JavaScript, TypeScript, Go, Rust, Python, and PHP (27 language patterns).
114
114
  - **Unified "All" Search** — Concurrent search across files, text, and symbols with automatic deduplication.
115
115
  - **Frecency Ranking** — SQLite-backed history database remembers which files you open for specific queries, floating high-value results to the top.
116
116
  - **"Changed Only" Filter** — Restricts search scope exclusively to files changed in the active git diff.
@@ -176,18 +176,8 @@ A vim-style status bar at the bottom displays the current mode (NORMAL/INSERT),
176
176
 
177
177
  ## Native Terminal UI (TUI) — *Experimental*
178
178
 
179
- > [!WARNING]
180
- > The TUI is **experimental**. The interface, keymap, and on-disk format of
181
- > `server.json` (`mode: "tui"`) may change in a minor release before
182
- > stabilisation. The web UI is the supported path for production workflows;
183
- > please open an issue before depending on the TUI for CI / agent automation.
184
- > The web review flow, plan review, and PR review are unaffected.
179
+ <img width="1624" height="1061" alt="image" src="https://github.com/user-attachments/assets/2756dbe5-6329-4d70-a8c0-ca61600c2154" />
185
180
 
186
- > [!IMPORTANT]
187
- > Native binaries are published as optional, platform-specific npm packages
188
- > for macOS, Windows, and glibc/musl Linux. The main package never compiles Rust
189
- > during installation and never installs a binary for the wrong platform. A
190
- > source build and `$PATH` remain supported fallbacks.
191
181
 
192
182
  `diffing --tui` opens an **opt-in native-Rust terminal interface** that mirrors the local code-review workflow — no browser or Electron. The renderer and headless tools share one sparse diff index. Review sessions publish a capability-scoped loopback API through the per-repository session registry; web and TUI reviews can run concurrently, while `server.json` points agent commands at the selected active session. Read-only viewers do not register a review session.
193
183
 
@@ -1,8 +1,8 @@
1
- import { d as getProjectStorageDir } from "./git-Czo96ymM.mjs";
2
- import { n as saveSettings, t as loadSettings } from "./settings-yK0GYpbn.mjs";
1
+ import { f as getProjectStorageDir } from "./git-BGj31GX-.mjs";
2
+ import { a as loadSettings, i as reviewSessionUrl, o as saveSettings, t as appendSessionToken } from "./session-url-sr7lXXVc.mjs";
3
3
  import { t as formatComments } from "./comment-format-B85NHZnG.mjs";
4
4
  import { n as formatPlanReview } from "./plan-format-BwJh5JSE.mjs";
5
- import { u as resolveActiveServerLock } from "./server-lock-CY0_1mcS.mjs";
5
+ import { h as SESSION_TOKEN_HEADER, u as resolveActiveServerLock } from "./server-lock-BNI8FKV1.mjs";
6
6
  import { a as CLI_AWAIT_REVIEW_TIMEOUT_HINT, i as CLI_AWAIT_PLAN_TIMEOUT_HINT, o as CLI_PLAN_SUBMIT_PARK_HINT } from "./handoff-LAFtmnHf.mjs";
7
7
  import { join } from "node:path";
8
8
  import { parseArgs } from "node:util";
@@ -25,6 +25,7 @@ const EXIT_NO_SERVER = 3;
25
25
  const EXIT_NOT_FOUND = 4;
26
26
  const EXIT_USAGE = 5;
27
27
  let activeCapability;
28
+ let activeAuthToken;
28
29
  /** Resolve the running server's base URL from the lockfile, or exit cleanly. */
29
30
  function baseUrl() {
30
31
  const lock = resolveActiveServerLock();
@@ -34,17 +35,41 @@ function baseUrl() {
34
35
  }
35
36
  const host = lock.host === "0.0.0.0" || lock.host === "::" ? "127.0.0.1" : lock.host;
36
37
  activeCapability = lock.mode === "tui" ? lock.capability : void 0;
38
+ activeAuthToken = lock.authToken;
37
39
  return `http://${host}:${lock.port}`;
38
40
  }
39
- /** Attach the per-session TUI capability while preserving ordinary web calls. */
41
+ /** Attach session credentials while preserving ordinary web calls. */
40
42
  function apiFetch(input, init = {}) {
41
43
  const headers = new Headers(init.headers);
42
44
  if (activeCapability) headers.set("X-Diffing-Capability", activeCapability);
45
+ if (activeAuthToken) headers.set(SESSION_TOKEN_HEADER, activeAuthToken);
43
46
  return fetch(input, {
44
47
  ...init,
45
48
  headers
46
49
  });
47
50
  }
51
+ function connectionErrorMessage(err) {
52
+ if (err instanceof Error) return err.message;
53
+ return String(err);
54
+ }
55
+ /** apiFetch wrapper that logs connection failures and returns null instead of throwing. */
56
+ async function tryApiFetch(input, init) {
57
+ try {
58
+ return await apiFetch(input, init);
59
+ } catch (err) {
60
+ console.error(`Failed to reach diffing server: ${connectionErrorMessage(err)}`);
61
+ return null;
62
+ }
63
+ }
64
+ function parseTimeoutSeconds(raw, flag = "--timeout") {
65
+ if (raw === void 0) return 570;
66
+ const t = Number(raw);
67
+ if (!Number.isFinite(t) || t <= 0) {
68
+ console.error(`${flag} must be a positive number of seconds.`);
69
+ return null;
70
+ }
71
+ return t;
72
+ }
48
73
  async function readStdin() {
49
74
  const chunks = [];
50
75
  for await (const chunk of process.stdin) chunks.push(chunk);
@@ -68,7 +93,9 @@ async function awaitReview(args) {
68
93
  },
69
94
  allowPositionals: false
70
95
  });
71
- const totalBudgetMs = (values.timeout ? Number(values.timeout) : 570) * 1e3;
96
+ const timeoutSeconds = parseTimeoutSeconds(values.timeout);
97
+ if (timeoutSeconds === null) return EXIT_USAGE;
98
+ const totalBudgetMs = timeoutSeconds * 1e3;
72
99
  const base = baseUrl();
73
100
  let agentId = typeof values["agent-id"] === "string" ? values["agent-id"] : void 0;
74
101
  try {
@@ -84,9 +111,8 @@ async function awaitReview(args) {
84
111
  if (reg.ok) agentId = (await reg.json()).agentId ?? agentId;
85
112
  } catch {}
86
113
  let sinceRound = 0;
87
- try {
88
- sinceRound = (await apiFetch(`${base}/api/review/status`).then((r) => r.json())).round ?? 0;
89
- } catch {}
114
+ const statusRes = await tryApiFetch(`${base}/api/review/status`);
115
+ if (statusRes?.ok) sinceRound = (await statusRes.json()).round ?? 0;
90
116
  const unregister = async () => {
91
117
  if (!agentId) return;
92
118
  try {
@@ -100,10 +126,15 @@ async function awaitReview(args) {
100
126
  res = await apiFetch(`${base}/api/review/await?timeoutMs=25000&sinceRound=${sinceRound}`, { signal: AbortSignal.timeout(3e4) });
101
127
  } catch (err) {
102
128
  if (err?.name === "TimeoutError") continue;
103
- console.error(`Failed to reach diffing server: ${err?.message ?? err}`);
129
+ console.error(`Failed to reach diffing server: ${connectionErrorMessage(err)}`);
104
130
  await unregister();
105
131
  return EXIT_NO_SERVER;
106
132
  }
133
+ if (!res.ok) {
134
+ console.error(`Failed to await review: HTTP ${res.status}`);
135
+ await unregister();
136
+ return 1;
137
+ }
107
138
  const result = await res.json();
108
139
  if (result.status === "released") {
109
140
  process.stdout.write(result.payload.commentXml + "\n");
@@ -139,12 +170,18 @@ async function reply(args) {
139
170
  return EXIT_USAGE;
140
171
  }
141
172
  let body = values.body;
142
- if (body === "-" || body === void 0) body = (await readStdin()).trim();
173
+ if (body === void 0) {
174
+ if (process.stdin.isTTY) {
175
+ console.error("Usage: diffing reply <commentId> --body <text> [--model <name>]");
176
+ return EXIT_USAGE;
177
+ }
178
+ body = (await readStdin()).trim();
179
+ } else if (body === "-") body = (await readStdin()).trim();
143
180
  if (!body) {
144
181
  console.error("A reply body is required (--body <text> or pipe via stdin).");
145
182
  return EXIT_USAGE;
146
183
  }
147
- const res = await apiFetch(`${baseUrl()}/api/comments/${commentId}/replies`, {
184
+ const res = await tryApiFetch(`${baseUrl()}/api/comments/${commentId}/replies`, {
148
185
  method: "POST",
149
186
  headers: { "Content-Type": "application/json" },
150
187
  body: JSON.stringify({
@@ -153,6 +190,7 @@ async function reply(args) {
153
190
  model: values.model
154
191
  })
155
192
  });
193
+ if (!res) return EXIT_NO_SERVER;
156
194
  if (res.status === 404) {
157
195
  console.error(`Comment ${commentId} not found.`);
158
196
  return EXIT_NOT_FOUND;
@@ -175,11 +213,12 @@ async function resolve$1(args) {
175
213
  console.error("Usage: diffing resolve <commentId>");
176
214
  return EXIT_USAGE;
177
215
  }
178
- const res = await apiFetch(`${baseUrl()}/api/comments/${commentId}`, {
216
+ const res = await tryApiFetch(`${baseUrl()}/api/comments/${commentId}`, {
179
217
  method: "PUT",
180
218
  headers: { "Content-Type": "application/json" },
181
219
  body: JSON.stringify({ status: "resolved" })
182
220
  });
221
+ if (!res) return EXIT_NO_SERVER;
183
222
  if (res.status === 404) {
184
223
  console.error(`Comment ${commentId} not found.`);
185
224
  return EXIT_NOT_FOUND;
@@ -202,11 +241,12 @@ async function unresolve(args) {
202
241
  console.error("Usage: diffing unresolve <commentId>");
203
242
  return EXIT_USAGE;
204
243
  }
205
- const res = await apiFetch(`${baseUrl()}/api/comments/${commentId}`, {
244
+ const res = await tryApiFetch(`${baseUrl()}/api/comments/${commentId}`, {
206
245
  method: "PUT",
207
246
  headers: { "Content-Type": "application/json" },
208
247
  body: JSON.stringify({ status: "open" })
209
248
  });
249
+ if (!res) return EXIT_NO_SERVER;
210
250
  if (res.status === 404) {
211
251
  console.error(`Comment ${commentId} not found.`);
212
252
  return EXIT_NOT_FOUND;
@@ -233,16 +273,23 @@ async function commentEdit(args) {
233
273
  return EXIT_USAGE;
234
274
  }
235
275
  let body = values.body;
236
- if (body === "-" || body === void 0) body = (await readStdin()).trim();
276
+ if (body === void 0) {
277
+ if (process.stdin.isTTY) {
278
+ console.error("Usage: diffing comment edit <commentId> --body <text>");
279
+ return EXIT_USAGE;
280
+ }
281
+ body = (await readStdin()).trim();
282
+ } else if (body === "-") body = (await readStdin()).trim();
237
283
  if (!body) {
238
284
  console.error("A body is required (--body <text> or stdin).");
239
285
  return EXIT_USAGE;
240
286
  }
241
- const res = await apiFetch(`${baseUrl()}/api/comments/${commentId}`, {
287
+ const res = await tryApiFetch(`${baseUrl()}/api/comments/${commentId}`, {
242
288
  method: "PUT",
243
289
  headers: { "Content-Type": "application/json" },
244
290
  body: JSON.stringify({ body })
245
291
  });
292
+ if (!res) return EXIT_NO_SERVER;
246
293
  if (res.status === 404) {
247
294
  console.error(`Comment ${commentId} not found.`);
248
295
  return EXIT_NOT_FOUND;
@@ -265,7 +312,8 @@ async function commentDelete(args) {
265
312
  console.error("Usage: diffing comment delete <commentId>");
266
313
  return EXIT_USAGE;
267
314
  }
268
- const res = await apiFetch(`${baseUrl()}/api/comments/${commentId}`, { method: "DELETE" });
315
+ const res = await tryApiFetch(`${baseUrl()}/api/comments/${commentId}`, { method: "DELETE" });
316
+ if (!res) return EXIT_NO_SERVER;
269
317
  if (res.status === 404) {
270
318
  console.error(`Comment ${commentId} not found.`);
271
319
  return EXIT_NOT_FOUND;
@@ -289,7 +337,13 @@ async function commentCmd(args) {
289
337
  }
290
338
  }
291
339
  async function url() {
292
- process.stdout.write(baseUrl() + "\n");
340
+ const lock = resolveActiveServerLock();
341
+ if (!lock) {
342
+ console.error("No diffing server running for this repo. Start one with `diffing`.");
343
+ process.exit(EXIT_NO_SERVER);
344
+ }
345
+ const printed = reviewSessionUrl(lock) ?? baseUrl();
346
+ process.stdout.write(`${printed}\n`);
293
347
  return EXIT_OK;
294
348
  }
295
349
  async function comments(args) {
@@ -302,9 +356,19 @@ async function comments(args) {
302
356
  },
303
357
  allowPositionals: false
304
358
  });
305
- const all = await apiFetch(`${baseUrl()}/api/comments`).then((r) => r.json());
359
+ const res = await tryApiFetch(`${baseUrl()}/api/comments`);
360
+ if (!res) return EXIT_NO_SERVER;
361
+ if (!res.ok) {
362
+ console.error(`Failed to fetch comments: HTTP ${res.status}`);
363
+ return 1;
364
+ }
365
+ const all = await res.json();
306
366
  const selected = values.open ? all.filter((c) => c.status === "open") : all;
307
367
  const format = values.format?.toLowerCase();
368
+ if (format && format !== "xml" && format !== "json" && format !== "md" && format !== "markdown") {
369
+ console.error("Unknown --format. Use xml, json, md, or markdown.");
370
+ return EXIT_USAGE;
371
+ }
308
372
  if (values.json || format === "json") process.stdout.write(JSON.stringify(selected, null, 2) + "\n");
309
373
  else if (format === "markdown" || format === "md") {
310
374
  const { formatCommentsMarkdown } = await import("./review-export-B63eRAVa.mjs");
@@ -349,9 +413,10 @@ function deriveTitle(body) {
349
413
  /** Long-poll the plan-review handoff until a decision arrives or time runs out. */
350
414
  async function pollPlanDecision(base, totalBudgetMs, seedSince) {
351
415
  let sinceRound = seedSince ?? 0;
352
- if (seedSince === void 0) try {
353
- sinceRound = (await apiFetch(`${base}/api/plan-review/status`).then((r) => r.json())).round ?? 0;
354
- } catch {}
416
+ if (seedSince === void 0) {
417
+ const statusRes = await tryApiFetch(`${base}/api/plan-review/status`);
418
+ if (statusRes?.ok) sinceRound = (await statusRes.json()).round ?? 0;
419
+ }
355
420
  const deadline = Date.now() + totalBudgetMs;
356
421
  while (Date.now() < deadline) {
357
422
  let res;
@@ -359,9 +424,13 @@ async function pollPlanDecision(base, totalBudgetMs, seedSince) {
359
424
  res = await apiFetch(`${base}/api/plan-review/await?timeoutMs=25000&sinceRound=${sinceRound}`, { signal: AbortSignal.timeout(3e4) });
360
425
  } catch (err) {
361
426
  if (err?.name === "TimeoutError") continue;
362
- console.error(`Failed to reach diffing server: ${err?.message ?? err}`);
427
+ console.error(`Failed to reach diffing server: ${connectionErrorMessage(err)}`);
363
428
  return EXIT_NO_SERVER;
364
429
  }
430
+ if (!res.ok) {
431
+ console.error(`Failed to await plan review: HTTP ${res.status}`);
432
+ return 1;
433
+ }
365
434
  const result = await res.json();
366
435
  if (result.status === "released") {
367
436
  process.stdout.write(result.payload.reviewXml + "\n");
@@ -428,10 +497,11 @@ async function planSubmit(args) {
428
497
  source = file;
429
498
  }
430
499
  let sinceRound = 0;
431
- if (values.wait) try {
432
- sinceRound = (await apiFetch(`${base}/api/plan-review/status`).then((r) => r.json())).round ?? 0;
433
- } catch {}
434
- const res = await apiFetch(`${base}/api/plans`, {
500
+ if (values.wait) {
501
+ const statusRes = await tryApiFetch(`${base}/api/plan-review/status`);
502
+ if (statusRes?.ok) sinceRound = (await statusRes.json()).round ?? 0;
503
+ }
504
+ const submitRes = await tryApiFetch(`${base}/api/plans`, {
435
505
  method: "POST",
436
506
  headers: { "Content-Type": "application/json" },
437
507
  body: JSON.stringify({
@@ -442,12 +512,13 @@ async function planSubmit(args) {
442
512
  model: values.model
443
513
  })
444
514
  });
445
- if (!res.ok) {
446
- console.error(`Failed to submit plan: HTTP ${res.status}`);
515
+ if (!submitRes) return EXIT_NO_SERVER;
516
+ if (!submitRes.ok) {
517
+ console.error(`Failed to submit plan: HTTP ${submitRes.status}`);
447
518
  return 1;
448
519
  }
449
- const plan = await res.json();
450
- console.error(`Submitted plan ${plan.id} (v${plan.version}) — review at ${base}/plan/${plan.id}`);
520
+ const plan = await submitRes.json();
521
+ console.error(`Submitted plan ${plan.id} (v${plan.version}) — review at ${appendSessionToken(`${base}/plan/${plan.id}`, activeAuthToken)}`);
451
522
  if (plan.sourcePath) console.error(`Source path: ${plan.sourcePath}`);
452
523
  if (!values.wait) console.error(CLI_PLAN_SUBMIT_PARK_HINT);
453
524
  if (values.saveSource) try {
@@ -463,7 +534,9 @@ async function planSubmit(args) {
463
534
  process.stdout.write(plan.id + "\n");
464
535
  return EXIT_OK;
465
536
  }
466
- return pollPlanDecision(base, (values.timeout ? Number(values.timeout) : 570) * 1e3, sinceRound);
537
+ const timeoutSeconds = parseTimeoutSeconds(values.timeout);
538
+ if (timeoutSeconds === null) return EXIT_USAGE;
539
+ return pollPlanDecision(base, timeoutSeconds * 1e3, sinceRound);
467
540
  }
468
541
  async function planAwait(args) {
469
542
  const { values } = parseArgs({
@@ -474,8 +547,9 @@ async function planAwait(args) {
474
547
  } },
475
548
  allowPositionals: false
476
549
  });
477
- const totalBudgetMs = (values.timeout ? Number(values.timeout) : 570) * 1e3;
478
- return pollPlanDecision(baseUrl(), totalBudgetMs);
550
+ const timeoutSeconds = parseTimeoutSeconds(values.timeout);
551
+ if (timeoutSeconds === null) return EXIT_USAGE;
552
+ return pollPlanDecision(baseUrl(), timeoutSeconds * 1e3);
479
553
  }
480
554
  async function planList(args) {
481
555
  const { values } = parseArgs({
@@ -483,7 +557,13 @@ async function planList(args) {
483
557
  options: { json: { type: "boolean" } },
484
558
  allowPositionals: false
485
559
  });
486
- const all = await apiFetch(`${baseUrl()}/api/plans`).then((r) => r.json());
560
+ const res = await tryApiFetch(`${baseUrl()}/api/plans`);
561
+ if (!res) return EXIT_NO_SERVER;
562
+ if (!res.ok) {
563
+ console.error(`Failed to list plans: HTTP ${res.status}`);
564
+ return 1;
565
+ }
566
+ const all = await res.json();
487
567
  if (values.json) {
488
568
  process.stdout.write(JSON.stringify(all, null, 2) + "\n");
489
569
  return EXIT_OK;
@@ -510,18 +590,29 @@ async function planShow(args) {
510
590
  const base = baseUrl();
511
591
  let planId = positionals[0];
512
592
  if (!planId) {
513
- const all = await apiFetch(`${base}/api/plans`).then((r) => r.json());
593
+ const listRes = await tryApiFetch(`${base}/api/plans`);
594
+ if (!listRes) return EXIT_NO_SERVER;
595
+ if (!listRes.ok) {
596
+ console.error(`Failed to list plans: HTTP ${listRes.status}`);
597
+ return 1;
598
+ }
599
+ const all = await listRes.json();
514
600
  if (all.length === 0) {
515
601
  console.error("No plans submitted yet.");
516
602
  return EXIT_NOT_FOUND;
517
603
  }
518
604
  planId = all[all.length - 1].id;
519
605
  }
520
- const res = await apiFetch(`${base}/api/plans/${planId}`);
606
+ const res = await tryApiFetch(`${base}/api/plans/${planId}`);
607
+ if (!res) return EXIT_NO_SERVER;
521
608
  if (res.status === 404) {
522
609
  console.error(`Plan ${planId} not found.`);
523
610
  return EXIT_NOT_FOUND;
524
611
  }
612
+ if (!res.ok) {
613
+ console.error(`Failed to load plan: HTTP ${res.status}`);
614
+ return 1;
615
+ }
525
616
  const plan = await res.json();
526
617
  const requestedVersion = values.version !== void 0 ? Number(values.version) : void 0;
527
618
  if (requestedVersion !== void 0 && (!Number.isFinite(requestedVersion) || requestedVersion < 1)) {
@@ -550,11 +641,16 @@ async function planVersions(args) {
550
641
  console.error("Usage: diffing plan versions <id> [--json]");
551
642
  return EXIT_USAGE;
552
643
  }
553
- const planRes = await apiFetch(`${base}/api/plans/${planId}`);
644
+ const planRes = await tryApiFetch(`${base}/api/plans/${planId}`);
645
+ if (!planRes) return EXIT_NO_SERVER;
554
646
  if (planRes.status === 404) {
555
647
  console.error(`Plan ${planId} not found.`);
556
648
  return EXIT_NOT_FOUND;
557
649
  }
650
+ if (!planRes.ok) {
651
+ console.error(`Failed to load plan: HTTP ${planRes.status}`);
652
+ return 1;
653
+ }
558
654
  const plan = await planRes.json();
559
655
  const versions = plan.versions ?? [];
560
656
  if (values.json) {
@@ -574,7 +670,9 @@ async function planVersions(args) {
574
670
  }
575
671
  /** Locate which plan owns a given comment id (comment ids are globally unique). */
576
672
  async function findCommentPlan(base, commentId) {
577
- return (await apiFetch(`${base}/api/plans`).then((r) => r.json())).find((p) => (p.comments ?? []).some((c) => c.id === commentId)) ?? null;
673
+ const res = await tryApiFetch(`${base}/api/plans`);
674
+ if (!res?.ok) return null;
675
+ return (await res.json()).find((p) => (p.comments ?? []).some((c) => c.id === commentId)) ?? null;
578
676
  }
579
677
  async function planReply(args) {
580
678
  const { values, positionals } = parseArgs({
@@ -597,7 +695,13 @@ async function planReply(args) {
597
695
  return EXIT_USAGE;
598
696
  }
599
697
  let body = values.body;
600
- if (body === "-" || body === void 0) body = (await readStdin()).trim();
698
+ if (body === void 0) {
699
+ if (process.stdin.isTTY) {
700
+ console.error("Usage: diffing plan reply <commentId> --body <text> [--model <name>]");
701
+ return EXIT_USAGE;
702
+ }
703
+ body = (await readStdin()).trim();
704
+ } else if (body === "-") body = (await readStdin()).trim();
601
705
  if (!body) {
602
706
  console.error("A reply body is required (--body <text> or pipe via stdin).");
603
707
  return EXIT_USAGE;
@@ -608,7 +712,7 @@ async function planReply(args) {
608
712
  console.error(`Plan comment ${commentId} not found.`);
609
713
  return EXIT_NOT_FOUND;
610
714
  }
611
- const res = await apiFetch(`${base}/api/plans/${plan.id}/comments/${commentId}/replies`, {
715
+ const res = await tryApiFetch(`${base}/api/plans/${plan.id}/comments/${commentId}/replies`, {
612
716
  method: "POST",
613
717
  headers: { "Content-Type": "application/json" },
614
718
  body: JSON.stringify({
@@ -617,6 +721,7 @@ async function planReply(args) {
617
721
  model: values.model
618
722
  })
619
723
  });
724
+ if (!res) return EXIT_NO_SERVER;
620
725
  if (!res.ok) {
621
726
  console.error(`Failed to reply: HTTP ${res.status}`);
622
727
  return 1;
@@ -641,11 +746,12 @@ async function planResolve(args) {
641
746
  console.error(`Plan comment ${commentId} not found.`);
642
747
  return EXIT_NOT_FOUND;
643
748
  }
644
- const res = await apiFetch(`${base}/api/plans/${plan.id}/comments/${commentId}`, {
749
+ const res = await tryApiFetch(`${base}/api/plans/${plan.id}/comments/${commentId}`, {
645
750
  method: "PUT",
646
751
  headers: { "Content-Type": "application/json" },
647
752
  body: JSON.stringify({ status: "resolved" })
648
753
  });
754
+ if (!res) return EXIT_NO_SERVER;
649
755
  if (!res.ok) {
650
756
  console.error(`Failed to resolve: HTTP ${res.status}`);
651
757
  return 1;
@@ -670,7 +776,7 @@ async function plan(args) {
670
776
  }
671
777
  }
672
778
  async function doctor() {
673
- const { runDoctor, formatDoctorReport } = await import("./doctor-D0Y3kOY7.mjs");
779
+ const { runDoctor, formatDoctorReport } = await import("./doctor-Bz9VHuBI.mjs");
674
780
  const report = await runDoctor({
675
781
  cwd: process.cwd(),
676
782
  cliImportMetaUrl: import.meta.url
@@ -679,16 +785,20 @@ async function doctor() {
679
785
  return report.ok ? EXIT_OK : 1;
680
786
  }
681
787
  async function completion(args) {
682
- const shell = args[0];
683
- if (!shell || args.includes("--help") || args.includes("-h")) {
788
+ if (args.includes("--help") || args.includes("-h")) {
684
789
  console.error("Usage: diffing completion <bash|zsh|fish>");
685
790
  console.error(" # Install examples:");
686
791
  console.error(" # diffing completion bash >> ~/.bashrc");
687
792
  console.error(" # diffing completion zsh > ~/.zfunc/_diffing");
688
793
  console.error(" # diffing completion fish > ~/.config/fish/completions/diffing.fish");
794
+ return EXIT_OK;
795
+ }
796
+ const shell = args[0];
797
+ if (!shell) {
798
+ console.error("Usage: diffing completion <bash|zsh|fish>");
689
799
  return EXIT_USAGE;
690
800
  }
691
- const { completionFor } = await import("./completions-BO2DUM-8.mjs");
801
+ const { completionFor } = await import("./completions-DvyV49HY.mjs");
692
802
  const script = completionFor(shell);
693
803
  if (!script) {
694
804
  console.error(`Unknown shell: ${shell}. Use bash, zsh, or fish.`);
@@ -788,11 +898,12 @@ Add --pretty for indented JSON. Compact JSON is the token-efficient default.`);
788
898
  return EXIT_USAGE;
789
899
  }
790
900
  const base = baseUrl();
901
+ const queryString = params.toString();
791
902
  let response;
792
903
  try {
793
- response = await apiFetch(`${base}${endpoint}${params.size ? `?${params}` : ""}`);
904
+ response = await apiFetch(`${base}${endpoint}${queryString ? `?${queryString}` : ""}`);
794
905
  } catch (error) {
795
- console.error(`Failed to reach diffing server: ${error?.message ?? error}`);
906
+ console.error(`Failed to reach diffing server: ${connectionErrorMessage(error)}`);
796
907
  return EXIT_NO_SERVER;
797
908
  }
798
909
  const body = await response.json().catch(() => ({ error: response.statusText }));
@@ -804,7 +915,7 @@ Add --pretty for indented JSON. Compact JSON is the token-efficient default.`);
804
915
  return EXIT_OK;
805
916
  }
806
917
  async function progress(args) {
807
- const { values } = parseArgs({
918
+ const { values, positionals } = parseArgs({
808
919
  args,
809
920
  options: {
810
921
  message: {
@@ -818,12 +929,12 @@ async function progress(args) {
818
929
  },
819
930
  allowPositionals: true
820
931
  });
821
- const message = values.message || (args.find((a) => !a.startsWith("-")) ?? "");
932
+ const message = values.message || positionals[0] || "";
822
933
  if (!message) {
823
934
  console.error("Usage: diffing progress --message \"Working on comment…\" [--model M] [--pct N]");
824
935
  return EXIT_USAGE;
825
936
  }
826
- const res = await apiFetch(`${baseUrl()}/api/agent/progress`, {
937
+ const res = await tryApiFetch(`${baseUrl()}/api/agent/progress`, {
827
938
  method: "POST",
828
939
  headers: { "Content-Type": "application/json" },
829
940
  body: JSON.stringify({
@@ -834,6 +945,7 @@ async function progress(args) {
834
945
  pct: values.pct != null ? Number(values.pct) : void 0
835
946
  })
836
947
  });
948
+ if (!res) return EXIT_NO_SERVER;
837
949
  if (!res.ok) {
838
950
  const err = await res.json().catch(() => ({}));
839
951
  console.error(err.error ?? res.statusText);
@@ -852,10 +964,10 @@ async function runSubcommand(name, args) {
852
964
  case "url": return url();
853
965
  case "plan": return plan(args);
854
966
  case "update":
855
- const { runUpdateCommand } = await import("./update-check-Copcz9eb.mjs");
967
+ const { runUpdateCommand } = await import("./update-check-BUfh4Y6c.mjs");
856
968
  return runUpdateCommand();
857
969
  case "gh":
858
- const { runGhSubcommand } = await import("./cli-gh-D0NfKpOp.mjs");
970
+ const { runGhSubcommand } = await import("./cli-gh-DI69gJGo.mjs");
859
971
  return runGhSubcommand(args);
860
972
  case "doctor": return doctor();
861
973
  case "completion": return completion(args);
@@ -863,7 +975,7 @@ async function runSubcommand(name, args) {
863
975
  case "inspect": return inspect(args);
864
976
  case "mode": return mode(args);
865
977
  case "sessions":
866
- const { runSessionsCommand } = await import("./session-manager-CYNchhVA.mjs");
978
+ const { runSessionsCommand } = await import("./session-manager-BKSZQqDJ.mjs");
867
979
  return runSessionsCommand(args);
868
980
  default:
869
981
  console.error(`Unknown subcommand: ${name}`);
@@ -1,5 +1,5 @@
1
1
  import { t as formatComments } from "./comment-format-B85NHZnG.mjs";
2
- import { u as resolveActiveServerLock } from "./server-lock-CY0_1mcS.mjs";
2
+ import { h as SESSION_TOKEN_HEADER, u as resolveActiveServerLock } from "./server-lock-BNI8FKV1.mjs";
3
3
  import { parseArgs } from "node:util";
4
4
  //#region src/cli-gh.ts
5
5
  /**
@@ -20,16 +20,27 @@ const EXIT_OK = 0;
20
20
  const EXIT_NO_SERVER = 3;
21
21
  const EXIT_NOT_FOUND = 4;
22
22
  const EXIT_USAGE = 5;
23
+ let activeAuthToken;
23
24
  function baseUrl() {
24
25
  const lock = resolveActiveServerLock();
25
26
  if (!lock) {
26
27
  console.error("No diffing server running for this repo. Start one with `diffing \"gh pr <ref>\"`.");
27
28
  process.exit(EXIT_NO_SERVER);
28
29
  }
29
- return `http://${lock.host === "0.0.0.0" || lock.host === "::" ? "127.0.0.1" : lock.host}:${lock.port}`;
30
+ const host = lock.host === "0.0.0.0" || lock.host === "::" ? "127.0.0.1" : lock.host;
31
+ activeAuthToken = lock.authToken;
32
+ return `http://${host}:${lock.port}`;
33
+ }
34
+ function apiFetch(input, init = {}) {
35
+ const headers = new Headers(init.headers);
36
+ if (activeAuthToken) headers.set(SESSION_TOKEN_HEADER, activeAuthToken);
37
+ return fetch(input, {
38
+ ...init,
39
+ headers
40
+ });
30
41
  }
31
42
  async function fetchJson(path) {
32
- const res = await fetch(`${baseUrl()}${path}`);
43
+ const res = await apiFetch(`${baseUrl()}${path}`);
33
44
  if (res.status === 404) return {
34
45
  ok: false,
35
46
  status: 404,
@@ -78,14 +89,14 @@ async function ghOverview(args) {
78
89
  return EXIT_OK;
79
90
  }
80
91
  async function ghStatus() {
81
- const overview = await fetch(`${baseUrl()}/api/gh/overview`);
92
+ const overview = await apiFetch(`${baseUrl()}/api/gh/overview`);
82
93
  if (overview.ok) {
83
94
  const session = await overview.json();
84
95
  const submitted = session.submittedAt ? `submitted ${new Date(session.submittedAt).toISOString()}` : "not submitted";
85
96
  console.log(`PR #${session.pullNumber} ${session.owner}/${session.repo} [${session.headSha.slice(0, 7)}] — ${session.counts.localDrafts} local draft(s), ${session.counts.unresolvedThreads} unresolved thread(s) — ${submitted}`);
86
97
  return EXIT_OK;
87
98
  }
88
- const res = await fetch(`${baseUrl()}/api/gh/session`);
99
+ const res = await apiFetch(`${baseUrl()}/api/gh/session`);
89
100
  if (res.status === 404) {
90
101
  console.error("No active PR session. Start one with `diffing \"gh pr <ref>\"`.");
91
102
  return EXIT_NOT_FOUND;
@@ -138,7 +149,7 @@ async function ghThreads(args) {
138
149
  return EXIT_USAGE;
139
150
  }
140
151
  params.set("format", format);
141
- const res = await fetch(`${baseUrl()}/api/gh/threads?${params}`);
152
+ const res = await apiFetch(`${baseUrl()}/api/gh/threads?${params}`);
142
153
  if (res.status === 404) {
143
154
  console.error("No active PR session.");
144
155
  return EXIT_NOT_FOUND;
@@ -181,7 +192,7 @@ async function ghReviews(args) {
181
192
  return EXIT_USAGE;
182
193
  }
183
194
  params.set("format", format);
184
- const res = await fetch(`${baseUrl()}/api/gh/reviews?${params}`);
195
+ const res = await apiFetch(`${baseUrl()}/api/gh/reviews?${params}`);
185
196
  if (res.status === 404) {
186
197
  console.error("No active PR session.");
187
198
  return EXIT_NOT_FOUND;
@@ -210,8 +221,8 @@ async function ghPrFetch(args) {
210
221
  return EXIT_USAGE;
211
222
  }
212
223
  const base = baseUrl();
213
- let res = await fetch(`${base}/api/gh/pr/refresh`, { method: "POST" });
214
- if (res.status === 404) res = await fetch(`${base}/api/gh/pr/init`, {
224
+ let res = await apiFetch(`${base}/api/gh/pr/refresh`, { method: "POST" });
225
+ if (res.status === 404) res = await apiFetch(`${base}/api/gh/pr/init`, {
215
226
  method: "POST",
216
227
  headers: { "Content-Type": "application/json" },
217
228
  body: JSON.stringify({ ref })
@@ -221,22 +232,21 @@ async function ghPrFetch(args) {
221
232
  console.error(`Failed to fetch PR: ${err.error ?? res.statusText}`);
222
233
  return 1;
223
234
  }
224
- const overviewRes = await fetch(`${base}/api/gh/overview`);
235
+ const overviewRes = await apiFetch(`${base}/api/gh/overview`);
225
236
  if (overviewRes.ok) {
226
237
  const result = await overviewRes.json();
227
238
  if (values.json) process.stdout.write(JSON.stringify(result, null, 2) + "\n");
228
239
  else console.log(`${result.owner}/${result.repo}#${result.pullNumber} ${result.url}`);
229
240
  return EXIT_OK;
230
241
  }
231
- const sessionRes = await fetch(`${base}/api/gh/session`);
242
+ const sessionRes = await apiFetch(`${base}/api/gh/session`);
232
243
  const result = sessionRes.ok ? await sessionRes.json() : await res.json();
233
244
  if (values.json) process.stdout.write(JSON.stringify(result, null, 2) + "\n");
234
245
  else console.log(`${result.owner}/${result.repo}#${result.pullNumber} ${result.url}`);
235
246
  return EXIT_OK;
236
247
  }
237
248
  async function ghPrListComments() {
238
- const base = baseUrl();
239
- const res = await fetch(`${base}/api/gh/pr-session/comments`);
249
+ const res = await apiFetch(`${baseUrl()}/api/gh/pr-session/comments`);
240
250
  if (res.status === 404) {
241
251
  console.error("No active PR session.");
242
252
  return EXIT_NOT_FOUND;
@@ -273,7 +283,7 @@ async function ghPrReview(args) {
273
283
  body: values.body ?? "",
274
284
  dryRun: values["dry-run"] === true
275
285
  };
276
- const res = await fetch(`${base}/api/gh/submit`, {
286
+ const res = await apiFetch(`${base}/api/gh/submit`, {
277
287
  method: "POST",
278
288
  headers: { "Content-Type": "application/json" },
279
289
  body: JSON.stringify(payload)