diffsplain 0.4.3 → 0.6.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 (331) hide show
  1. package/README.md +17 -12
  2. package/dist/assets/abap-CLvhMVsD.js +1 -0
  3. package/dist/assets/actionscript-3--17pq3dv.js +1 -0
  4. package/dist/assets/ada-C5qYipkI.js +1 -0
  5. package/dist/assets/andromeeda-vGVdxbeo.js +1 -0
  6. package/dist/assets/angular-html-vBvPnd6a.js +1 -0
  7. package/dist/assets/angular-ts-CDzF1Z6a.js +1 -0
  8. package/dist/assets/apache-U0d_L8uA.js +1 -0
  9. package/dist/assets/apex-VAyPSnFM.js +1 -0
  10. package/dist/assets/apl-Bm9bxvP7.js +1 -0
  11. package/dist/assets/applescript-CCn79oCD.js +1 -0
  12. package/dist/assets/ara-4CJ0cIlV.js +1 -0
  13. package/dist/assets/asciidoc-DE70LPWp.js +1 -0
  14. package/dist/assets/asm-Cmm7eHzH.js +1 -0
  15. package/dist/assets/astro-RNrNWCYO.js +1 -0
  16. package/dist/assets/aurora-x-CDeNXAV0.js +1 -0
  17. package/dist/assets/awk-BWXHIvNe.js +1 -0
  18. package/dist/assets/ayu-dark-DluEY0Gj.js +1 -0
  19. package/dist/assets/ayu-light-C3h-C4tm.js +1 -0
  20. package/dist/assets/ayu-mirage-Bqwy1Gya.js +1 -0
  21. package/dist/assets/ballerina-B7ZEbQpA.js +1 -0
  22. package/dist/assets/bat-Bo4NYOV-.js +1 -0
  23. package/dist/assets/beancount-D-usSTwE.js +1 -0
  24. package/dist/assets/berry-DKpUyyne.js +1 -0
  25. package/dist/assets/bibtex-Ci_nEsc7.js +1 -0
  26. package/dist/assets/bicep-CUHmPFLl.js +1 -0
  27. package/dist/assets/bird2-C6vDhewU.js +1 -0
  28. package/dist/assets/blade-On-NBYUv.js +1 -0
  29. package/dist/assets/bsl-BkkzgIyY.js +1 -0
  30. package/dist/assets/c-hRmhFgD0.js +1 -0
  31. package/dist/assets/c3-BFHwR3_K.js +1 -0
  32. package/dist/assets/cadence-CQ2zXKGN.js +1 -0
  33. package/dist/assets/cairo-DLTphjLi.js +1 -0
  34. package/dist/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
  35. package/dist/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
  36. package/dist/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
  37. package/dist/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
  38. package/dist/assets/clarity-SemFz856.js +1 -0
  39. package/dist/assets/clojure-DqKBuwfJ.js +1 -0
  40. package/dist/assets/cmake-Bj61d0ZC.js +1 -0
  41. package/dist/assets/cobol-CIqc3k2t.js +1 -0
  42. package/dist/assets/codeowners-C8r90Shi.js +1 -0
  43. package/dist/assets/codeql-oeQT6MSM.js +1 -0
  44. package/dist/assets/coffee-Cd5EyvvS.js +1 -0
  45. package/dist/assets/common-lisp-Cv5bFMCO.js +1 -0
  46. package/dist/assets/coq-BrsZFFmf.js +1 -0
  47. package/dist/assets/cpp-zXFAAp_S.js +1 -0
  48. package/dist/assets/crystal-DRYY4cSw.js +1 -0
  49. package/dist/assets/csharp-oqKa8noW.js +1 -0
  50. package/dist/assets/css-C4op_MsD.js +1 -0
  51. package/dist/assets/csv-Dx-8-gkx.js +1 -0
  52. package/dist/assets/cue-CE9AQfxI.js +1 -0
  53. package/dist/assets/cypher-ClKdZ_lG.js +1 -0
  54. package/dist/assets/d-qD-0Kul2.js +1 -0
  55. package/dist/assets/dark-plus-Cs2F2srj.js +1 -0
  56. package/dist/assets/dart-CnvKMtbv.js +1 -0
  57. package/dist/assets/dax-BkyTk9wS.js +1 -0
  58. package/dist/assets/desktop-Dlh5hvp9.js +1 -0
  59. package/dist/assets/diff-woXpYk--.js +1 -0
  60. package/dist/assets/docker-IyjqRm3v.js +1 -0
  61. package/dist/assets/dotenv-_5a1GRtc.js +1 -0
  62. package/dist/assets/dracula-BHWKrbxM.js +1 -0
  63. package/dist/assets/dracula-soft-5eyTD99u.js +1 -0
  64. package/dist/assets/dream-maker-DW3nJb8Q.js +1 -0
  65. package/dist/assets/edge-d3rJkErf.js +1 -0
  66. package/dist/assets/elixir-DPqlJhYM.js +1 -0
  67. package/dist/assets/elm-DgU37I8a.js +1 -0
  68. package/dist/assets/emacs-lisp-B4R74twV.js +1 -0
  69. package/dist/assets/erb-CZVB_ntC.js +1 -0
  70. package/dist/assets/erlang-Cphh6RMH.js +1 -0
  71. package/dist/assets/everforest-dark-sB-x3p7T.js +1 -0
  72. package/dist/assets/everforest-light-Df2xbC6M.js +1 -0
  73. package/dist/assets/fennel-DQxkIbk2.js +1 -0
  74. package/dist/assets/fish-BJitypiv.js +1 -0
  75. package/dist/assets/fluent-C03EYrpw.js +1 -0
  76. package/dist/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
  77. package/dist/assets/fortran-free-form-CYNrtFtB.js +1 -0
  78. package/dist/assets/fsharp-D13ZGOAj.js +1 -0
  79. package/dist/assets/gdresource-C0sCabJj.js +1 -0
  80. package/dist/assets/gdscript-Cp2uCuqX.js +1 -0
  81. package/dist/assets/gdshader-CBce3t8t.js +1 -0
  82. package/dist/assets/genie-CV2tkWYe.js +1 -0
  83. package/dist/assets/gherkin-DExj1W_8.js +1 -0
  84. package/dist/assets/git-commit-BSykSTBG.js +1 -0
  85. package/dist/assets/git-rebase-hUkltHZG.js +1 -0
  86. package/dist/assets/github-dark-C-LZuMrd.js +1 -0
  87. package/dist/assets/github-dark-default-DXG-b-1a.js +1 -0
  88. package/dist/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
  89. package/dist/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
  90. package/dist/assets/github-light-EUqPIrTm.js +1 -0
  91. package/dist/assets/github-light-default-BXViO-2h.js +1 -0
  92. package/dist/assets/github-light-high-contrast-B68TUdTA.js +1 -0
  93. package/dist/assets/gleam-CSRkHgEL.js +1 -0
  94. package/dist/assets/glimmer-js-5XOT9GQ8.js +1 -0
  95. package/dist/assets/glimmer-ts-DT7D0Kfq.js +1 -0
  96. package/dist/assets/glsl-Br4_Eh5O.js +1 -0
  97. package/dist/assets/gn-ilITqXS6.js +1 -0
  98. package/dist/assets/gnuplot-7GGW24-e.js +1 -0
  99. package/dist/assets/go-rLFTqkRN.js +1 -0
  100. package/dist/assets/graphql--BmZ_AYP.js +1 -0
  101. package/dist/assets/groovy-CacY0gHj.js +1 -0
  102. package/dist/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
  103. package/dist/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
  104. package/dist/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  105. package/dist/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
  106. package/dist/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
  107. package/dist/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
  108. package/dist/assets/hack-CMdqGDoA.js +1 -0
  109. package/dist/assets/haml-DLEOHGmg.js +1 -0
  110. package/dist/assets/handlebars-BfUftoV0.js +1 -0
  111. package/dist/assets/haskell-D8IpX4py.js +1 -0
  112. package/dist/assets/haxe-OTjmBuCE.js +1 -0
  113. package/dist/assets/hcl-Dh228itO.js +1 -0
  114. package/dist/assets/hjson-CxZEssPk.js +1 -0
  115. package/dist/assets/hlsl-Cvrh5tZx.js +1 -0
  116. package/dist/assets/horizon-CE9ld1lL.js +1 -0
  117. package/dist/assets/horizon-bright-DSNQnXHK.js +1 -0
  118. package/dist/assets/houston-CsvMBhTu.js +1 -0
  119. package/dist/assets/html-derivative-D5cZE6C4.js +1 -0
  120. package/dist/assets/html-uOgx2iYC.js +1 -0
  121. package/dist/assets/http-cW9c66J_.js +1 -0
  122. package/dist/assets/hurl-BztURO2n.js +1 -0
  123. package/dist/assets/hxml-B0Qn7Nwc.js +1 -0
  124. package/dist/assets/hy-CZbG8q4J.js +1 -0
  125. package/dist/assets/imba-DsUTQ-LC.js +1 -0
  126. package/dist/assets/{index-BB6eHlnY.css → index-C2p_1iAk.css} +1 -1
  127. package/dist/assets/index-DZFM4-3L.js +1568 -0
  128. package/dist/assets/ini-B5eOa1yu.js +1 -0
  129. package/dist/assets/java-Cy4mnKaj.js +1 -0
  130. package/dist/assets/javascript-_Z02t_9Q.js +1 -0
  131. package/dist/assets/jinja-BppBm5gt.js +1 -0
  132. package/dist/assets/jison-Dzns436M.js +1 -0
  133. package/dist/assets/json-BYkfLOry.js +1 -0
  134. package/dist/assets/json5-BR5RXkoi.js +1 -0
  135. package/dist/assets/jsonc-CYpm1nAK.js +1 -0
  136. package/dist/assets/jsonl-CmCQp5Yx.js +1 -0
  137. package/dist/assets/jsonnet-CJTPZ8u_.js +1 -0
  138. package/dist/assets/jssm-DXw9l8Rf.js +1 -0
  139. package/dist/assets/jsx-DtAm8NUb.js +1 -0
  140. package/dist/assets/julia-CLIMRuh0.js +1 -0
  141. package/dist/assets/just-DMg47an6.js +1 -0
  142. package/dist/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
  143. package/dist/assets/kanagawa-lotus-BN08jTvb.js +1 -0
  144. package/dist/assets/kanagawa-wave-CTweb8Dz.js +1 -0
  145. package/dist/assets/kdl-CsD5j6eV.js +1 -0
  146. package/dist/assets/kotlin-DhhofPvG.js +1 -0
  147. package/dist/assets/kusto-C7mF5XQf.js +1 -0
  148. package/dist/assets/laserwave-C_8bwKvT.js +1 -0
  149. package/dist/assets/latex-D05ztCOx.js +1 -0
  150. package/dist/assets/lean-CewbzKMR.js +1 -0
  151. package/dist/assets/less-DVTAwKKz.js +1 -0
  152. package/dist/assets/light-plus-DVQuIRkW.js +1 -0
  153. package/dist/assets/liquid-DpImQR4t.js +1 -0
  154. package/dist/assets/llvm-Cm23YOpf.js +1 -0
  155. package/dist/assets/log-BNLmms1o.js +1 -0
  156. package/dist/assets/logo-Cluzi2Zq.js +1 -0
  157. package/dist/assets/lua--ZHUYQUU.js +1 -0
  158. package/dist/assets/luau-FMPmPwt6.js +1 -0
  159. package/dist/assets/make-Dixweg8N.js +1 -0
  160. package/dist/assets/markdown-BYOwaDjH.js +1 -0
  161. package/dist/assets/marko-Dh3Xi08i.js +1 -0
  162. package/dist/assets/material-theme-Bm3Qr25_.js +1 -0
  163. package/dist/assets/material-theme-darker-2IIEA8gg.js +1 -0
  164. package/dist/assets/material-theme-lighter-uhdI0v04.js +1 -0
  165. package/dist/assets/material-theme-ocean-CHQ94UKr.js +1 -0
  166. package/dist/assets/material-theme-palenight-B5W6OYN7.js +1 -0
  167. package/dist/assets/matlab-D7qyCx1q.js +1 -0
  168. package/dist/assets/mdc-Br6Pt78u.js +1 -0
  169. package/dist/assets/mdx-DQZ5AkYe.js +1 -0
  170. package/dist/assets/mermaid-Bk4SNUv9.js +1 -0
  171. package/dist/assets/min-dark-BSWPekZh.js +1 -0
  172. package/dist/assets/min-light-DDpmG2fV.js +1 -0
  173. package/dist/assets/mipsasm-BMqwQI7S.js +1 -0
  174. package/dist/assets/mojo-BgCJLMeH.js +1 -0
  175. package/dist/assets/monokai-CdkpiU2Y.js +1 -0
  176. package/dist/assets/moonbit-CaWjb8XO.js +1 -0
  177. package/dist/assets/move-B1IS1UjX.js +1 -0
  178. package/dist/assets/narrat-_X_XdTYD.js +1 -0
  179. package/dist/assets/nextflow-BJtWHP5T.js +1 -0
  180. package/dist/assets/nextflow-groovy-DJMQeKeT.js +1 -0
  181. package/dist/assets/nginx-CwSU6U6d.js +1 -0
  182. package/dist/assets/night-owl-DhmEMT88.js +1 -0
  183. package/dist/assets/night-owl-light-eJ-hLW7d.js +1 -0
  184. package/dist/assets/nim-CBbTwyeq.js +1 -0
  185. package/dist/assets/nix-IvuFDN5E.js +1 -0
  186. package/dist/assets/nord-Cb4Vim4T.js +1 -0
  187. package/dist/assets/nushell-DcLAeLz5.js +1 -0
  188. package/dist/assets/objective-c-D1A_Heim.js +1 -0
  189. package/dist/assets/objective-cpp-BsSzOQcm.js +1 -0
  190. package/dist/assets/ocaml-O90oeIOV.js +1 -0
  191. package/dist/assets/odin-B1RWQWA5.js +1 -0
  192. package/dist/assets/one-dark-pro-CLwyXe_n.js +1 -0
  193. package/dist/assets/one-light-D7Lr4KcI.js +1 -0
  194. package/dist/assets/openscad-BUDT5pXO.js +1 -0
  195. package/dist/assets/pascal-4ZHwLPI5.js +1 -0
  196. package/dist/assets/perl-D3jQu3LN.js +1 -0
  197. package/dist/assets/php-BMeXBzlU.js +1 -0
  198. package/dist/assets/pierre-dark-CpLgRqie.js +1 -0
  199. package/dist/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
  200. package/dist/assets/pierre-dark-soft-kZQmAZld.js +1 -0
  201. package/dist/assets/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
  202. package/dist/assets/pierre-dark-vibrant-CpQYzh95.js +1 -0
  203. package/dist/assets/pierre-light-CoaEpmwp.js +1 -0
  204. package/dist/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
  205. package/dist/assets/pierre-light-soft-lWLdNTOI.js +1 -0
  206. package/dist/assets/pierre-light-tritanopia-CEbqgOJL.js +1 -0
  207. package/dist/assets/pierre-light-vibrant-D80Fkn33.js +1 -0
  208. package/dist/assets/pkl-ot-7Btpt.js +1 -0
  209. package/dist/assets/plastic-DQwYfKfQ.js +1 -0
  210. package/dist/assets/plsql-DGHpHOYJ.js +1 -0
  211. package/dist/assets/po-BiJDBrnU.js +1 -0
  212. package/dist/assets/poimandres-DRFjx7u4.js +1 -0
  213. package/dist/assets/polar-C7UOKdEL.js +1 -0
  214. package/dist/assets/postcss-BXeXVLqQ.js +1 -0
  215. package/dist/assets/powerquery-DNMTfnFr.js +1 -0
  216. package/dist/assets/powershell-DshXNtvi.js +1 -0
  217. package/dist/assets/prisma-BsRQq5mF.js +1 -0
  218. package/dist/assets/prolog-iXnhIJG7.js +1 -0
  219. package/dist/assets/proto-DB4EqR-F.js +1 -0
  220. package/dist/assets/pug-BGdY1g5E.js +1 -0
  221. package/dist/assets/puppet-CDv2pdJW.js +1 -0
  222. package/dist/assets/purescript-9MfHhQsQ.js +1 -0
  223. package/dist/assets/python-gzcpVVnB.js +1 -0
  224. package/dist/assets/qml-DsT5biza.js +1 -0
  225. package/dist/assets/qmldir-DCQb3MpD.js +1 -0
  226. package/dist/assets/qss-Fe1Jh2GI.js +1 -0
  227. package/dist/assets/r-CbS9PfN5.js +1 -0
  228. package/dist/assets/racket-DcIDlBhZ.js +1 -0
  229. package/dist/assets/raku-B3gFvitq.js +1 -0
  230. package/dist/assets/razor-Bwm8roHi.js +1 -0
  231. package/dist/assets/red-CJ3rzSJv.js +1 -0
  232. package/dist/assets/reg-CRGYupPL.js +1 -0
  233. package/dist/assets/regexp-Bc_9DyAu.js +1 -0
  234. package/dist/assets/rel-BtDbiS_P.js +1 -0
  235. package/dist/assets/riscv-Ckw8ddFX.js +1 -0
  236. package/dist/assets/ron-VUp2lXgN.js +1 -0
  237. package/dist/assets/rose-pine-BthvhNj6.js +1 -0
  238. package/dist/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
  239. package/dist/assets/rose-pine-moon-hon4tzzS.js +1 -0
  240. package/dist/assets/rosmsg-CAekHB0j.js +1 -0
  241. package/dist/assets/rst-Cj1Aii91.js +1 -0
  242. package/dist/assets/ruby-BPMtFZnc.js +1 -0
  243. package/dist/assets/rust-Cfkwpbl8.js +1 -0
  244. package/dist/assets/sas-CoOau1t2.js +1 -0
  245. package/dist/assets/sass-DXrisJhu.js +1 -0
  246. package/dist/assets/scala-DKOlJaKm.js +1 -0
  247. package/dist/assets/scheme-DQCgrYNe.js +1 -0
  248. package/dist/assets/scss-CvfaI808.js +1 -0
  249. package/dist/assets/sdbl-bTVj8UrX.js +1 -0
  250. package/dist/assets/shaderlab-TOUzSsQk.js +1 -0
  251. package/dist/assets/shellscript-B0C-TdLE.js +1 -0
  252. package/dist/assets/shellsession-UhmLiqcA.js +1 -0
  253. package/dist/assets/slack-dark-DnToyrRv.js +1 -0
  254. package/dist/assets/slack-ochin-B2OO5cIa.js +1 -0
  255. package/dist/assets/smalltalk-B16xEiuN.js +1 -0
  256. package/dist/assets/snazzy-light-4G7pJPwS.js +1 -0
  257. package/dist/assets/solarized-dark-DV17i1UV.js +1 -0
  258. package/dist/assets/solarized-light-DSh2HLQt.js +1 -0
  259. package/dist/assets/solidity-CKzVLygQ.js +1 -0
  260. package/dist/assets/soy-D419u0RL.js +1 -0
  261. package/dist/assets/sparql-D_iOobhT.js +1 -0
  262. package/dist/assets/splunk-BC2Px7Mm.js +1 -0
  263. package/dist/assets/sql-Do9k0rRn.js +1 -0
  264. package/dist/assets/ssh-config-BgfXC-Er.js +1 -0
  265. package/dist/assets/stata-x47J6BC4.js +1 -0
  266. package/dist/assets/stylus-B6D30XZt.js +1 -0
  267. package/dist/assets/surrealql-BERQ6pHu.js +1 -0
  268. package/dist/assets/svelte-dRWkyqKW.js +1 -0
  269. package/dist/assets/swift-DonLKvLd.js +1 -0
  270. package/dist/assets/synthwave-84-nFMaYfgc.js +1 -0
  271. package/dist/assets/system-verilog-DJ5XKQeo.js +1 -0
  272. package/dist/assets/systemd-BxMlprV5.js +1 -0
  273. package/dist/assets/talonscript-CohzipZa.js +1 -0
  274. package/dist/assets/tasl-DMoTqEGO.js +1 -0
  275. package/dist/assets/tcl-CZd0xW_V.js +1 -0
  276. package/dist/assets/templ-CTq-KoWN.js +1 -0
  277. package/dist/assets/terraform-DswuEJGm.js +1 -0
  278. package/dist/assets/tex-CdRGjyYI.js +1 -0
  279. package/dist/assets/tokyo-night-oM2G3aXe.js +1 -0
  280. package/dist/assets/toml-CcmNWLt0.js +1 -0
  281. package/dist/assets/ts-tags-CgaMqyVb.js +1 -0
  282. package/dist/assets/tsv-sltzmVWM.js +1 -0
  283. package/dist/assets/tsx-cpBQKcPG.js +1 -0
  284. package/dist/assets/turtle-ByJddavk.js +1 -0
  285. package/dist/assets/twig-vbs_PM4-.js +1 -0
  286. package/dist/assets/typescript-Cc--nwIo.js +1 -0
  287. package/dist/assets/typespec-BRdr0IET.js +1 -0
  288. package/dist/assets/typst-DI99ib-x.js +1 -0
  289. package/dist/assets/v-DETTlOr0.js +1 -0
  290. package/dist/assets/vala-zf12oZj6.js +1 -0
  291. package/dist/assets/vb-Djn5o6TS.js +1 -0
  292. package/dist/assets/verilog-CiiDBU1e.js +1 -0
  293. package/dist/assets/vesper-DdrHHSXu.js +1 -0
  294. package/dist/assets/vhdl-BroJfC0k.js +1 -0
  295. package/dist/assets/viml-DvXPmvsu.js +1 -0
  296. package/dist/assets/vitesse-black-fwtXNY1n.js +1 -0
  297. package/dist/assets/vitesse-dark-BZCL-v6S.js +1 -0
  298. package/dist/assets/vitesse-light-VbXTXTou.js +1 -0
  299. package/dist/assets/vue-CgHwdBmB.js +1 -0
  300. package/dist/assets/vue-html-BHfoMw47.js +1 -0
  301. package/dist/assets/vue-vine-_lVRp_NK.js +1 -0
  302. package/dist/assets/vyper-CgoNMtux.js +1 -0
  303. package/dist/assets/wasm-BnjxR4X6.js +1 -0
  304. package/dist/assets/wasm-ByWQv1Qj.js +1 -0
  305. package/dist/assets/wenyan-C8pVoKbM.js +1 -0
  306. package/dist/assets/wgsl-BsKzXJz4.js +1 -0
  307. package/dist/assets/wikitext-ClFFjSW2.js +1 -0
  308. package/dist/assets/wit-DdvCle-K.js +1 -0
  309. package/dist/assets/wolfram-DLL8P-h_.js +1 -0
  310. package/dist/assets/xml-G4NVmTde.js +1 -0
  311. package/dist/assets/xsl-s0so2M1i.js +1 -0
  312. package/dist/assets/yaml-CpsmW05t.js +1 -0
  313. package/dist/assets/zenscript-BnlCZFoB.js +1 -0
  314. package/dist/assets/zig-CMLA9XwU.js +1 -0
  315. package/dist/index.html +2 -2
  316. package/package.json +52 -23
  317. package/scripts/access-token.mjs +21 -0
  318. package/scripts/build-diff-data.mjs +297 -62
  319. package/scripts/cache.mjs +301 -0
  320. package/scripts/cli-args.mjs +206 -57
  321. package/scripts/coding-agents.mjs +279 -162
  322. package/scripts/dev.mjs +218 -0
  323. package/scripts/doctor.mjs +265 -46
  324. package/scripts/generate-summaries.mjs +760 -260
  325. package/scripts/mock-agent.mjs +165 -0
  326. package/scripts/present.mjs +394 -85
  327. package/scripts/presenter-runtime.mjs +148 -0
  328. package/scripts/serve-built.mjs +343 -71
  329. package/scripts/summary-path.mjs +24 -7
  330. package/scripts/support-record.mjs +242 -0
  331. package/dist/assets/index-D5201POe.js +0 -10
@@ -3,14 +3,20 @@
3
3
  import { execFileSync, spawnSync } from 'node:child_process';
4
4
  import { createHash } from 'node:crypto';
5
5
  import {
6
+ closeSync,
7
+ constants,
6
8
  existsSync,
9
+ fstatSync,
10
+ lstatSync,
7
11
  mkdirSync,
12
+ openSync,
8
13
  readFileSync,
14
+ readlinkSync,
9
15
  renameSync,
10
16
  statSync,
11
17
  writeFileSync,
12
18
  } from 'node:fs';
13
- import { dirname, relative, resolve } from 'node:path';
19
+ import { basename, dirname, relative, resolve } from 'node:path';
14
20
  import { fileURLToPath } from 'node:url';
15
21
  import { summaryPath } from './summary-path.mjs';
16
22
 
@@ -26,6 +32,10 @@ const option = (name) => {
26
32
  if (!value || value.startsWith('--')) fail(`${name} needs a value`);
27
33
  return value;
28
34
  };
35
+ const options = (name) =>
36
+ args.flatMap((argument, index) =>
37
+ argument === name && args[index + 1] ? [args[index + 1]] : [],
38
+ );
29
39
  const has = (name) => args.includes(name);
30
40
 
31
41
  if (has('--help')) {
@@ -52,7 +62,7 @@ Options:
52
62
 
53
63
  const repo = resolve(option('--repo') || process.cwd());
54
64
  const output = resolve(option('--output') || '.cache/diff-data.json');
55
- const excludedOutput = option('--exclude-output');
65
+ const excludedOutputs = options('--exclude-output');
56
66
  const baseOption = option('--base');
57
67
  const headOption = option('--head');
58
68
  const prOption = option('--pr');
@@ -79,7 +89,18 @@ const cacheRoot = cacheOption
79
89
  : resolve(projectRoot, '.cache/git');
80
90
  const remoteMode = Boolean(prOption || branchOption);
81
91
  const watching = has('--watch');
92
+ const watchContent = has('--watch-content');
82
93
  const ignoreSummaryWatch = has('--ignore-summary-watch');
94
+ const noSummaries = has('--no-summaries');
95
+ const interval = (name, fallback) => {
96
+ const value = Number(process.env[name]);
97
+ return Number.isFinite(value) && value > 0 ? value : fallback;
98
+ };
99
+ const watchInterval = interval('DIFFSPLAIN_WATCH_INTERVAL_MS', 2_000);
100
+ const remoteRefreshInterval = interval(
101
+ 'DIFFSPLAIN_REMOTE_REFRESH_INTERVAL_MS',
102
+ 30_000,
103
+ );
83
104
 
84
105
  if (prOption && branchOption) fail('--pr and --branch cannot be used together');
85
106
  if (prOption && (baseOption || headOption)) fail('--pr cannot be used with --base or --head');
@@ -109,11 +130,13 @@ const repoPath = (file) => {
109
130
  const path = relative(repo, file).replaceAll('\\', '/');
110
131
  return path && path !== '..' && !path.startsWith('../') ? path : undefined;
111
132
  };
133
+ const summariesRepoPath = repoPath(summariesPath);
112
134
  const excludedPaths = new Set(
113
135
  [
114
- repoPath(summariesPath),
136
+ summariesRepoPath,
137
+ summariesRepoPath ? `${summariesRepoPath}.lock` : undefined,
115
138
  repoPath(output),
116
- excludedOutput ? repoPath(resolve(excludedOutput)) : undefined,
139
+ ...excludedOutputs.map((path) => repoPath(resolve(path))),
117
140
  ].filter(Boolean),
118
141
  );
119
142
 
@@ -176,6 +199,22 @@ const completeChangeSummary = (value) =>
176
199
  completeText(value.why) &&
177
200
  completeList(value.highlights) &&
178
201
  completeList(value.risks);
202
+ const failedFileRecords = (value) =>
203
+ Array.isArray(value)
204
+ ? value
205
+ .filter(
206
+ (item) =>
207
+ item &&
208
+ typeof item.path === 'string' &&
209
+ item.path.trim() &&
210
+ typeof item.reason === 'string' &&
211
+ item.reason.trim(),
212
+ )
213
+ .map((item) => ({
214
+ path: item.path.trim(),
215
+ reason: item.reason.trim(),
216
+ }))
217
+ : [];
179
218
 
180
219
  function fileSummary(path, value) {
181
220
  return {
@@ -255,31 +294,45 @@ function parseNumstat(raw) {
255
294
  function compactSnippet(patch, limit = 180) {
256
295
  const lines = patch.split('\n');
257
296
  if (lines.length <= limit) return patch;
258
- const header = lines
259
- .filter(
260
- (line) =>
261
- !line.startsWith('@@') &&
262
- !line.startsWith('+') &&
263
- !line.startsWith('-') &&
264
- !line.startsWith(' '),
265
- )
266
- .slice(0, 8);
267
- const hunks = [];
268
- let open = false;
269
- for (const line of lines) {
270
- if (line.startsWith('@@')) {
271
- if (hunks.length >= 72) break;
272
- open = true;
273
- hunks.push(line);
274
- continue;
297
+ const firstHunk = lines.findIndex((line) => line.startsWith('@@'));
298
+ if (firstHunk < 0) return patch;
299
+
300
+ const output = lines.slice(0, firstHunk);
301
+ let cursor = firstHunk;
302
+ while (cursor < lines.length && output.length < limit) {
303
+ const nextHunk = lines.findIndex(
304
+ (line, index) => index > cursor && line.startsWith('@@'),
305
+ );
306
+ const end = nextHunk < 0 ? lines.length : nextHunk;
307
+ const hunk = lines.slice(cursor, end);
308
+ const remaining = limit - output.length;
309
+
310
+ if (hunk.length <= remaining) {
311
+ output.push(...hunk);
312
+ } else {
313
+ const match = hunk[0].match(
314
+ /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@(.*)$/,
315
+ );
316
+ if (!match || remaining < 2) break;
317
+
318
+ const body = hunk.slice(1, remaining);
319
+ let oldCount = 0;
320
+ let newCount = 0;
321
+ for (const line of body) {
322
+ if (line === '\') continue;
323
+ if (!line.startsWith('+')) oldCount += 1;
324
+ if (!line.startsWith('-')) newCount += 1;
325
+ }
326
+ output.push(
327
+ `@@ -${match[1]},${oldCount} +${match[2]},${newCount} @@${match[3]}`,
328
+ ...body,
329
+ );
275
330
  }
276
- if (open && hunks.length < 72) hunks.push(line);
331
+
332
+ if (nextHunk < 0 || output.length >= limit) break;
333
+ cursor = nextHunk;
277
334
  }
278
- return [
279
- ...header,
280
- ...hunks,
281
- '... diff truncated; see patch for full content ...',
282
- ].join('\n');
335
+ return output.join('\n');
283
336
  }
284
337
 
285
338
  function normalizeBranch(value, remoteName) {
@@ -297,12 +350,24 @@ function normalizeBranch(value, remoteName) {
297
350
  }
298
351
 
299
352
  function resolveRemote() {
300
- const configured = tryRepo(['remote', 'get-url', remoteOption]);
301
- if (configured) return { name: remoteOption, url: configured };
353
+ const configured = tryRepo([
354
+ 'config',
355
+ '--get-all',
356
+ `remote.${remoteOption}.url`,
357
+ ])
358
+ .split('\n')
359
+ .find(Boolean);
360
+ if (configured) {
361
+ return {
362
+ name: remoteOption,
363
+ url: configured,
364
+ fetchUrl: tryRepo(['remote', 'get-url', remoteOption]) || configured,
365
+ };
366
+ }
302
367
  if (remoteOption === 'origin') {
303
368
  throw new Error(`Git remote "origin" was not found in ${repo}`);
304
369
  }
305
- return { name: remoteOption, url: remoteOption };
370
+ return { name: remoteOption, url: remoteOption, fetchUrl: remoteOption };
306
371
  }
307
372
 
308
373
  function bareCache(remoteUrl) {
@@ -373,6 +438,34 @@ function remoteDefaultBranch(remoteUrl) {
373
438
  return remoteDefaultBranchInfo(remoteUrl).name;
374
439
  }
375
440
 
441
+ function remoteContainsCommits(remoteUrl, commits) {
442
+ let raw;
443
+ try {
444
+ raw = runRepo(['ls-remote', remoteUrl]);
445
+ } catch {
446
+ return false;
447
+ }
448
+ const tips = [
449
+ ...new Set(
450
+ raw
451
+ .split('\n')
452
+ .map((line) => line.trim().split(/\s+/, 1)[0])
453
+ .filter(Boolean),
454
+ ),
455
+ ];
456
+ return commits.every((commit) =>
457
+ tips.some((tip) => {
458
+ if (tip === commit) return true;
459
+ const result = spawnSync(
460
+ 'git',
461
+ ['-C', repo, 'merge-base', '--is-ancestor', commit, tip],
462
+ { stdio: 'ignore' },
463
+ );
464
+ return result.status === 0;
465
+ }),
466
+ );
467
+ }
468
+
376
469
  function localDefaultBranch(remote) {
377
470
  if (baseOption) return { name: baseOption };
378
471
 
@@ -492,7 +585,7 @@ function resolveBranchTarget() {
492
585
  const remote = resolveRemote();
493
586
  const branch = normalizeBranch(branchOption, remote.name);
494
587
  const baseBranch = normalizeBranch(
495
- baseOption || remoteDefaultBranch(remote.url),
588
+ baseOption || remoteDefaultBranch(remote.fetchUrl),
496
589
  remote.name,
497
590
  );
498
591
  const cache = bareCache(remote.url);
@@ -502,7 +595,7 @@ function resolveBranchTarget() {
502
595
  .slice(0, 16);
503
596
  const baseRef = `refs/diffsplain/branch/${key}/base`;
504
597
  const headRef = `refs/diffsplain/branch/${key}/head`;
505
- fetchInto(cache, remote.url, [
598
+ fetchInto(cache, remote.fetchUrl, [
506
599
  `+refs/heads/${baseBranch}:${baseRef}`,
507
600
  `+refs/heads/${branch}:${headRef}`,
508
601
  ]);
@@ -521,6 +614,7 @@ function resolveBranchTarget() {
521
614
  remote,
522
615
  sourceRepositoryUrl: repository?.webUrl,
523
616
  baseRepositoryUrl: repository?.webUrl,
617
+ comparisonCommitsOnRemote: true,
524
618
  target: {
525
619
  kind: 'branch',
526
620
  remote: remote.name,
@@ -548,7 +642,7 @@ function resolvePullRequestTarget() {
548
642
  .slice(0, 16);
549
643
  const baseRef = `refs/diffsplain/pr/${key}/base`;
550
644
  const headRef = `refs/diffsplain/pr/${key}/head`;
551
- fetchInto(cache, remote.url, [
645
+ fetchInto(cache, remote.fetchUrl, [
552
646
  `+refs/heads/${pr.baseRefName}:${baseRef}`,
553
647
  `+refs/pull/${pr.number}/head:${headRef}`,
554
648
  ]);
@@ -586,6 +680,7 @@ function resolvePullRequestTarget() {
586
680
  pr.url.replace(/\/pull\/\d+(?:\/.*)?$/, ''),
587
681
  baseRepositoryUrl:
588
682
  repository?.webUrl || pr.url.replace(/\/pull\/\d+(?:\/.*)?$/, ''),
683
+ comparisonCommitsOnRemote: true,
589
684
  target: {
590
685
  kind: 'pull-request',
591
686
  remote: remote.name,
@@ -632,6 +727,9 @@ function resolveCheckoutTarget() {
632
727
  const repository = githubRepository(remoteUrl);
633
728
  const headLabel = branch || currentHead;
634
729
  const hasCommittedChanges = mergeBaseOid !== currentHead;
730
+ const hasUncommittedChanges = Boolean(
731
+ tryRepo(['status', '--porcelain=v1', '-z']),
732
+ );
635
733
  const isDefaultBranchCheckout = branch === defaultBranch.name;
636
734
 
637
735
  return {
@@ -645,6 +743,12 @@ function resolveCheckoutTarget() {
645
743
  remote,
646
744
  sourceRepositoryUrl: repository?.webUrl,
647
745
  baseRepositoryUrl: repository?.webUrl,
746
+ comparisonCommitsOnRemote:
747
+ !hasUncommittedChanges &&
748
+ Boolean(
749
+ remote?.url &&
750
+ remoteContainsCommits(remote.url, [mergeBaseOid, currentHead]),
751
+ ),
648
752
  target: {
649
753
  kind: 'checkout',
650
754
  ...(remote ? { remote: remote.name } : {}),
@@ -698,6 +802,12 @@ function resolveLocalTarget() {
698
802
  baseRepositoryUrl: worktree
699
803
  ? undefined
700
804
  : githubRepository(remoteUrl)?.webUrl,
805
+ comparisonCommitsOnRemote:
806
+ !worktree &&
807
+ Boolean(
808
+ remoteUrl &&
809
+ remoteContainsCommits(remoteUrl, [resolvedBase, resolvedHead]),
810
+ ),
701
811
  target: worktree
702
812
  ? { kind: 'worktree', base: { ref: 'HEAD', oid: currentHead || null } }
703
813
  : {
@@ -798,6 +908,13 @@ function githubFileUrl(repositoryUrl, ref, path) {
798
908
  return `${repositoryUrl}/blob/${encodeURIComponent(ref)}/${filePath}`;
799
909
  }
800
910
 
911
+ function githubComparisonUrl(repositoryUrl, base, head) {
912
+ if (!repositoryUrl || !base || !head || head === 'WORKTREE') {
913
+ return undefined;
914
+ }
915
+ return `${repositoryUrl}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`;
916
+ }
917
+
801
918
  function build() {
802
919
  const localWorkspace =
803
920
  tryRepo(['rev-parse', '--is-inside-work-tree']) === 'true';
@@ -806,7 +923,7 @@ function build() {
806
923
  }
807
924
  const target = resolveTarget();
808
925
  const remoteRepository = githubRepository(target.remote?.url);
809
- const summaryDoc = readJson(summariesPath, {}) || {};
926
+ const summaryDoc = noSummaries ? {} : readJson(summariesPath, {}) || {};
810
927
  const allTrackedFiles = parseNameStatus(
811
928
  target.runGit([
812
929
  'diff',
@@ -873,6 +990,13 @@ function build() {
873
990
  file.status === 'deleted' ? target.base : target.head,
874
991
  file.path,
875
992
  );
993
+ const comparisonUrl = githubComparisonUrl(
994
+ target.comparisonCommitsOnRemote
995
+ ? target.sourceRepositoryUrl
996
+ : undefined,
997
+ target.base,
998
+ target.head,
999
+ );
876
1000
  return {
877
1001
  path: file.path,
878
1002
  ...(file.oldPath ? { oldPath: file.oldPath } : {}),
@@ -885,6 +1009,7 @@ function build() {
885
1009
  patch: textPatch,
886
1010
  snippet: binary ? '' : compactSnippet(textPatch),
887
1011
  ...(sourceUrl ? { sourceUrl } : {}),
1012
+ ...(comparisonUrl ? { comparisonUrl } : {}),
888
1013
  };
889
1014
  });
890
1015
 
@@ -912,39 +1037,64 @@ function build() {
912
1037
  )
913
1038
  .digest('hex');
914
1039
  const generatedFor =
1040
+ !noSummaries &&
915
1041
  typeof summaryDoc.meta?.reviewFingerprint === 'string'
916
1042
  ? summaryDoc.meta.reviewFingerprint
917
1043
  : undefined;
918
- const summariesAreFresh = !generatedFor || generatedFor === reviewFingerprint;
1044
+ const summariesAreFresh =
1045
+ !noSummaries && (!generatedFor || generatedFor === reviewFingerprint);
919
1046
  const sourceSummaries = summariesAreFresh ? summaryDoc : {};
1047
+ const failedFiles = summariesAreFresh
1048
+ ? failedFileRecords(summaryDoc.meta?.failedFiles)
1049
+ : [];
1050
+ const summaryErrors = summariesAreFresh
1051
+ ? cleanList(summaryDoc.meta?.errors)
1052
+ : [];
1053
+ const failureByPath = new Map(
1054
+ failedFiles.map((failure) => [failure.path, failure.reason]),
1055
+ );
1056
+ const emptyReviewComplete =
1057
+ filesWithoutSummaries.length === 0 &&
1058
+ generatedFor === reviewFingerprint &&
1059
+ sourceSummaries.meta?.status === 'complete';
920
1060
  const summariesAreComplete =
921
1061
  summariesAreFresh &&
922
- completeChangeSummary(sourceSummaries.change) &&
923
- filesWithoutSummaries.every((file) =>
924
- completeFileSummary(sourceSummaries.files?.[file.path]),
925
- );
926
- const completedFiles = filesWithoutSummaries.filter((file) =>
927
- completeFileSummary(sourceSummaries.files?.[file.path]),
928
- ).length;
1062
+ failedFiles.length === 0 &&
1063
+ summaryErrors.length === 0 &&
1064
+ (emptyReviewComplete ||
1065
+ (completeChangeSummary(sourceSummaries.change) &&
1066
+ filesWithoutSummaries.every((file) =>
1067
+ completeFileSummary(sourceSummaries.files?.[file.path]),
1068
+ )));
1069
+ const completedFiles = noSummaries
1070
+ ? 0
1071
+ : filesWithoutSummaries.filter((file) =>
1072
+ completeFileSummary(sourceSummaries.files?.[file.path]),
1073
+ ).length;
929
1074
  const storedStatus = summaryDoc.meta?.status;
930
- const noteStatus = summariesAreComplete
931
- ? 'complete'
932
- : !summariesAreFresh
933
- ? 'stale'
934
- : ['generating', 'failed'].includes(storedStatus)
935
- ? storedStatus
936
- : 'idle';
1075
+ const noteStatus = noSummaries
1076
+ ? 'idle'
1077
+ : summariesAreComplete
1078
+ ? 'complete'
1079
+ : !summariesAreFresh
1080
+ ? 'stale'
1081
+ : ['generating', 'failed'].includes(storedStatus)
1082
+ ? storedStatus
1083
+ : 'idle';
937
1084
  const files = filesWithoutSummaries.map((file) => ({
938
1085
  ...file,
939
1086
  summary: fileSummary(file.path, sourceSummaries.files?.[file.path]),
940
1087
  noteReady: Boolean(
941
1088
  completeFileSummary(sourceSummaries.files?.[file.path]),
942
1089
  ),
1090
+ ...(failureByPath.has(file.path)
1091
+ ? { noteFailure: failureByPath.get(file.path) }
1092
+ : {}),
943
1093
  }));
944
1094
  const change = changeSummary(sourceSummaries.change, target.changeDefaults);
945
1095
  const content = {
946
1096
  repo: {
947
- name: remoteRepository?.name || repo.split('/').pop(),
1097
+ name: remoteRepository?.name || basename(repo),
948
1098
  root: localWorkspace ? repo : target.remote?.url || repo,
949
1099
  base: target.base,
950
1100
  head: target.head,
@@ -965,9 +1115,14 @@ function build() {
965
1115
  status: noteStatus,
966
1116
  completedFiles,
967
1117
  totalFiles: filesWithoutSummaries.length,
1118
+ ...(failedFiles.length ? { failedFiles } : {}),
1119
+ ...(summaryErrors.length ? { errors: summaryErrors } : {}),
968
1120
  ...(typeof summaryDoc.meta?.model === 'string'
969
1121
  ? { model: summaryDoc.meta.model }
970
1122
  : {}),
1123
+ ...(typeof summaryDoc.meta?.agent === 'string'
1124
+ ? { agent: summaryDoc.meta.agent }
1125
+ : {}),
971
1126
  ...(typeof summaryDoc.meta?.reasoning === 'string'
972
1127
  ? { reasoning: summaryDoc.meta.reasoning }
973
1128
  : {}),
@@ -997,9 +1152,52 @@ function build() {
997
1152
  return true;
998
1153
  }
999
1154
 
1155
+ function untrackedFileKind(stat) {
1156
+ if (stat.isFile()) return 'file';
1157
+ if (stat.isSymbolicLink()) return 'symlink';
1158
+ if (stat.isDirectory()) return 'directory';
1159
+ return 'other';
1160
+ }
1161
+
1162
+ function fingerprintUntrackedPath(content, path) {
1163
+ const absolutePath = resolve(repo, path);
1164
+ const stat = lstatSync(absolutePath, { bigint: true });
1165
+ content.update(path);
1166
+ content.update('\0');
1167
+ content.update(untrackedFileKind(stat));
1168
+ content.update('\0');
1169
+ content.update(String(stat.size));
1170
+ content.update('\0');
1171
+ content.update(String(stat.mtimeNs));
1172
+ content.update('\0');
1173
+ if (stat.isFile()) {
1174
+ const descriptor = openSync(
1175
+ absolutePath,
1176
+ constants.O_RDONLY | constants.O_NOFOLLOW,
1177
+ );
1178
+ try {
1179
+ const opened = fstatSync(descriptor, { bigint: true });
1180
+ if (
1181
+ !opened.isFile()
1182
+ || opened.dev !== stat.dev
1183
+ || opened.ino !== stat.ino
1184
+ ) {
1185
+ throw new Error(`${path} changed while its fingerprint was read`);
1186
+ }
1187
+ content.update(readFileSync(descriptor));
1188
+ } finally {
1189
+ closeSync(descriptor);
1190
+ }
1191
+ content.update('\0');
1192
+ } else if (stat.isSymbolicLink()) {
1193
+ content.update(readlinkSync(absolutePath));
1194
+ content.update('\0');
1195
+ }
1196
+ }
1197
+
1000
1198
  function fingerprint() {
1001
1199
  let summariesTime = '';
1002
- if (!ignoreSummaryWatch) {
1200
+ if (!ignoreSummaryWatch && !noSummaries) {
1003
1201
  try {
1004
1202
  summariesTime = String(statSync(summariesPath).mtimeMs);
1005
1203
  } catch {}
@@ -1012,9 +1210,26 @@ function fingerprint() {
1012
1210
  summariesTime,
1013
1211
  ].join('|');
1014
1212
  }
1213
+ const content = createHash('sha256');
1214
+ content.update(
1215
+ tryRepo(['diff', '--no-ext-diff', '--no-textconv', '--binary', 'HEAD', '--']),
1216
+ );
1217
+ const untracked = tryRepo([
1218
+ 'ls-files',
1219
+ '--others',
1220
+ '--exclude-standard',
1221
+ '-z',
1222
+ ])
1223
+ .split('\0')
1224
+ .filter((path) => path && !excludedPaths.has(path))
1225
+ .sort();
1226
+ for (const path of untracked) {
1227
+ fingerprintUntrackedPath(content, path);
1228
+ }
1015
1229
  return [
1016
1230
  tryRepo(['rev-parse', 'HEAD']),
1017
1231
  tryRepo(['status', '--porcelain=v1', '--untracked-files=all']),
1232
+ content.digest('hex'),
1018
1233
  summariesTime,
1019
1234
  ].join('|');
1020
1235
  }
@@ -1026,25 +1241,45 @@ const refresh = () => {
1026
1241
  return true;
1027
1242
  } catch (error) {
1028
1243
  console.error(error.message);
1029
- if (!watching) process.exitCode = 1;
1244
+ process.exitCode = 1;
1030
1245
  return false;
1031
1246
  }
1032
1247
  };
1033
1248
 
1034
1249
  const started = refresh();
1035
1250
  if (watching && started) {
1036
- let last = fingerprint();
1251
+ let last;
1037
1252
  let remoteWait = 0;
1038
- setInterval(() => {
1039
- const next = fingerprint();
1040
- remoteWait += 2_000;
1041
- const remoteDue = remoteMode && remoteWait >= 30_000;
1042
- if (next !== last || remoteDue) {
1043
- last = next;
1044
- remoteWait = 0;
1045
- refresh();
1253
+ let watcher;
1254
+ const stopWatching = (error) => {
1255
+ console.error(error instanceof Error ? error.message : String(error));
1256
+ process.exitCode = 1;
1257
+ if (watcher) clearInterval(watcher);
1258
+ };
1259
+ const poll = () => {
1260
+ try {
1261
+ const next = fingerprint();
1262
+ if (last === undefined) {
1263
+ last = next;
1264
+ return true;
1265
+ }
1266
+ remoteWait += watchInterval;
1267
+ const remoteDue = remoteMode && remoteWait >= remoteRefreshInterval;
1268
+ if (next !== last || remoteDue || watchContent) {
1269
+ last = next;
1270
+ remoteWait = 0;
1271
+ if (!refresh()) {
1272
+ clearInterval(watcher);
1273
+ return false;
1274
+ }
1275
+ }
1276
+ return true;
1277
+ } catch (error) {
1278
+ stopWatching(error);
1279
+ return false;
1046
1280
  }
1047
- }, 2_000);
1281
+ };
1282
+ if (poll()) watcher = setInterval(poll, watchInterval);
1048
1283
  } else if (watching) {
1049
1284
  process.exitCode = 1;
1050
1285
  }