jj-plus 0.10.10

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 (404) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +102 -0
  3. package/assets/jj-plus-icon.png +0 -0
  4. package/dist/_virtual/_rolldown/runtime.cjs +23 -0
  5. package/dist/bin.cjs +112 -0
  6. package/dist/bin.cjs.map +1 -0
  7. package/dist/cli/options.cjs +376 -0
  8. package/dist/cli/options.cjs.map +1 -0
  9. package/dist/cli/timeline-json.cjs +29 -0
  10. package/dist/cli/timeline-json.cjs.map +1 -0
  11. package/dist/extension/blame-codelens.cjs +228 -0
  12. package/dist/extension/blame-codelens.cjs.map +1 -0
  13. package/dist/extension/command-runner.cjs +99 -0
  14. package/dist/extension/command-runner.cjs.map +1 -0
  15. package/dist/extension/constants.cjs +56 -0
  16. package/dist/extension/constants.cjs.map +1 -0
  17. package/dist/extension/editor-extra-features.cjs +464 -0
  18. package/dist/extension/editor-extra-features.cjs.map +1 -0
  19. package/dist/extension/history-adapters.cjs +702 -0
  20. package/dist/extension/history-adapters.cjs.map +1 -0
  21. package/dist/extension/index.cjs +657 -0
  22. package/dist/extension/index.cjs.map +1 -0
  23. package/dist/extension/repo-timeline-panel.cjs +402 -0
  24. package/dist/extension/repo-timeline-panel.cjs.map +1 -0
  25. package/dist/extension/resolve-file-path.cjs +16 -0
  26. package/dist/extension/resolve-file-path.cjs.map +1 -0
  27. package/dist/extension/revision-diff-nav.cjs +169 -0
  28. package/dist/extension/revision-diff-nav.cjs.map +1 -0
  29. package/dist/extension/settings.cjs +41 -0
  30. package/dist/extension/settings.cjs.map +1 -0
  31. package/dist/extension/timeline-at-line.cjs +72 -0
  32. package/dist/extension/timeline-at-line.cjs.map +1 -0
  33. package/dist/extension/timeline-panel.cjs +1113 -0
  34. package/dist/extension/timeline-panel.cjs.map +1 -0
  35. package/dist/extension/timeline-service.cjs +1154 -0
  36. package/dist/extension/timeline-service.cjs.map +1 -0
  37. package/dist/extension/uri-utils.cjs +75 -0
  38. package/dist/extension/uri-utils.cjs.map +1 -0
  39. package/dist/package.cjs +11 -0
  40. package/dist/package.cjs.map +1 -0
  41. package/dist/shared/blame.cjs +211 -0
  42. package/dist/shared/blame.cjs.map +1 -0
  43. package/dist/shared/diff-content-search.cjs +23 -0
  44. package/dist/shared/diff-content-search.cjs.map +1 -0
  45. package/dist/shared/diff-helpers.cjs +12 -0
  46. package/dist/shared/diff-helpers.cjs.map +1 -0
  47. package/dist/shared/diff-stats.cjs +129 -0
  48. package/dist/shared/diff-stats.cjs.map +1 -0
  49. package/dist/shared/file-oplog.cjs +82 -0
  50. package/dist/shared/file-oplog.cjs.map +1 -0
  51. package/dist/shared/history-helpers.cjs +257 -0
  52. package/dist/shared/history-helpers.cjs.map +1 -0
  53. package/dist/shared/history-search.cjs +85 -0
  54. package/dist/shared/history-search.cjs.map +1 -0
  55. package/dist/shared/jj-revset-suggestions.cjs +41 -0
  56. package/dist/shared/jj-revset-suggestions.cjs.map +1 -0
  57. package/dist/shared/line-history.cjs +181 -0
  58. package/dist/shared/line-history.cjs.map +1 -0
  59. package/dist/shared/list-file-revisions.cjs +36 -0
  60. package/dist/shared/list-file-revisions.cjs.map +1 -0
  61. package/dist/shared/non-textual-details.cjs +43 -0
  62. package/dist/shared/non-textual-details.cjs.map +1 -0
  63. package/dist/shared/resolve-file-path.cjs +14 -0
  64. package/dist/shared/resolve-file-path.cjs.map +1 -0
  65. package/dist/shared/revision-diff-availability.cjs +18 -0
  66. package/dist/shared/revision-diff-availability.cjs.map +1 -0
  67. package/dist/shared/revision-diff-pair.cjs +42 -0
  68. package/dist/shared/revision-diff-pair.cjs.map +1 -0
  69. package/dist/shared/revset.cjs +16 -0
  70. package/dist/shared/revset.cjs.map +1 -0
  71. package/dist/shared/timeline-model.cjs +29 -0
  72. package/dist/shared/timeline-model.cjs.map +1 -0
  73. package/dist/standalone/server.cjs +1733 -0
  74. package/dist/standalone/server.cjs.map +1 -0
  75. package/dist/webview/timeline-template.cjs +214 -0
  76. package/dist/webview/timeline-template.cjs.map +1 -0
  77. package/package.json +320 -0
  78. package/webview-dist/assets/worker-DuV13XDT.js +161 -0
  79. package/webview-dist/chunks/abap-CLvhMVsD.js +1 -0
  80. package/webview-dist/chunks/actionscript-3-Cs6JJXT5.js +1 -0
  81. package/webview-dist/chunks/ada-C5qYipkI.js +1 -0
  82. package/webview-dist/chunks/ahk-CA9gdOdF.js +1 -0
  83. package/webview-dist/chunks/ahk2-_6rzW9BS.js +1 -0
  84. package/webview-dist/chunks/andromeeda-vGVdxbeo.js +1 -0
  85. package/webview-dist/chunks/angular-html-DTpR04n4.js +1 -0
  86. package/webview-dist/chunks/angular-ts-BCtbMvbl.js +1 -0
  87. package/webview-dist/chunks/apache-U0d_L8uA.js +1 -0
  88. package/webview-dist/chunks/apex-KFGFyKwG.js +1 -0
  89. package/webview-dist/chunks/apl-BMZuN1Ql.js +1 -0
  90. package/webview-dist/chunks/applescript-CCn79oCD.js +1 -0
  91. package/webview-dist/chunks/ara-4CJ0cIlV.js +1 -0
  92. package/webview-dist/chunks/asciidoc-SCjQUq34.js +1 -0
  93. package/webview-dist/chunks/asm-Cmm7eHzH.js +1 -0
  94. package/webview-dist/chunks/astro-DrbV4Z7r.js +1 -0
  95. package/webview-dist/chunks/aurora-x-CDeNXAV0.js +1 -0
  96. package/webview-dist/chunks/awk-BWXHIvNe.js +1 -0
  97. package/webview-dist/chunks/ayu-dark-DluEY0Gj.js +1 -0
  98. package/webview-dist/chunks/ayu-light-C3h-C4tm.js +1 -0
  99. package/webview-dist/chunks/ayu-mirage-Bqwy1Gya.js +1 -0
  100. package/webview-dist/chunks/ballerina-B7ZEbQpA.js +1 -0
  101. package/webview-dist/chunks/bat-qdxAdBWQ.js +1 -0
  102. package/webview-dist/chunks/beancount-D-usSTwE.js +1 -0
  103. package/webview-dist/chunks/berry-DKpUyyne.js +1 -0
  104. package/webview-dist/chunks/bibtex-Ci_nEsc7.js +1 -0
  105. package/webview-dist/chunks/bicep-CUHmPFLl.js +1 -0
  106. package/webview-dist/chunks/bird2-CYIUgYqB.js +1 -0
  107. package/webview-dist/chunks/blade-oPV8S6rR.js +1 -0
  108. package/webview-dist/chunks/bsl-_VjlB9mv.js +1 -0
  109. package/webview-dist/chunks/c-DYf-3tob.js +1 -0
  110. package/webview-dist/chunks/c3-D0apG41V.js +1 -0
  111. package/webview-dist/chunks/cadence-CQ2zXKGN.js +1 -0
  112. package/webview-dist/chunks/cairo-DLTphjLi.js +1 -0
  113. package/webview-dist/chunks/catppuccin-frappe-C9Q5zVZY.js +1 -0
  114. package/webview-dist/chunks/catppuccin-latte-CtsyrtPq.js +1 -0
  115. package/webview-dist/chunks/catppuccin-macchiato-R8nAf1vR.js +1 -0
  116. package/webview-dist/chunks/catppuccin-mocha-DjuaAJKi.js +1 -0
  117. package/webview-dist/chunks/chapel-DY-WYB1D.js +1 -0
  118. package/webview-dist/chunks/clarity-CtfBBspg.js +1 -0
  119. package/webview-dist/chunks/clojure-DqKBuwfJ.js +1 -0
  120. package/webview-dist/chunks/cmake-Bj61d0ZC.js +1 -0
  121. package/webview-dist/chunks/cobol-DvdX_6CO.js +1 -0
  122. package/webview-dist/chunks/codeowners-C8r90Shi.js +1 -0
  123. package/webview-dist/chunks/codeql-oeQT6MSM.js +1 -0
  124. package/webview-dist/chunks/coffee-C1kO7jr_.js +1 -0
  125. package/webview-dist/chunks/common-lisp-Cv5bFMCO.js +1 -0
  126. package/webview-dist/chunks/coq-DuBRPxYg.js +1 -0
  127. package/webview-dist/chunks/cpp-CoSarUrI.js +1 -0
  128. package/webview-dist/chunks/crystal-SLJeZ5EP.js +1 -0
  129. package/webview-dist/chunks/csharp-oqKa8noW.js +1 -0
  130. package/webview-dist/chunks/css-cfScyrSP.js +1 -0
  131. package/webview-dist/chunks/csv-Dx-8-gkx.js +1 -0
  132. package/webview-dist/chunks/cue-CE9AQfxI.js +1 -0
  133. package/webview-dist/chunks/cypher-ClKdZ_lG.js +1 -0
  134. package/webview-dist/chunks/d-qD-0Kul2.js +1 -0
  135. package/webview-dist/chunks/dark-plus-Cs2F2srj.js +1 -0
  136. package/webview-dist/chunks/dart-CnvKMtbv.js +1 -0
  137. package/webview-dist/chunks/dax-BkyTk9wS.js +1 -0
  138. package/webview-dist/chunks/desktop-Dlh5hvp9.js +1 -0
  139. package/webview-dist/chunks/diff-woXpYk--.js +1 -0
  140. package/webview-dist/chunks/docker-IyjqRm3v.js +1 -0
  141. package/webview-dist/chunks/dotenv-_5a1GRtc.js +1 -0
  142. package/webview-dist/chunks/dracula-BHWKrbxM.js +1 -0
  143. package/webview-dist/chunks/dracula-soft-5eyTD99u.js +1 -0
  144. package/webview-dist/chunks/dream-maker-DW3nJb8Q.js +1 -0
  145. package/webview-dist/chunks/edge-lvBr3t3s.js +1 -0
  146. package/webview-dist/chunks/elixir-BLoPe0KG.js +1 -0
  147. package/webview-dist/chunks/elm-BveBINBn.js +1 -0
  148. package/webview-dist/chunks/emacs-lisp-c_oH4hRZ.js +1 -0
  149. package/webview-dist/chunks/erb-Bmf8z4ph.js +1 -0
  150. package/webview-dist/chunks/erlang-Cphh6RMH.js +1 -0
  151. package/webview-dist/chunks/everforest-dark-sB-x3p7T.js +1 -0
  152. package/webview-dist/chunks/everforest-light-Df2xbC6M.js +1 -0
  153. package/webview-dist/chunks/fennel-DQxkIbk2.js +1 -0
  154. package/webview-dist/chunks/fish-BJitypiv.js +1 -0
  155. package/webview-dist/chunks/fluent-C03EYrpw.js +1 -0
  156. package/webview-dist/chunks/fortran-fixed-form-DEKoE2YW.js +1 -0
  157. package/webview-dist/chunks/fortran-free-form-CYNrtFtB.js +1 -0
  158. package/webview-dist/chunks/fsharp-D13ZGOAj.js +1 -0
  159. package/webview-dist/chunks/gdresource-xMC7jr7x.js +1 -0
  160. package/webview-dist/chunks/gdscript-DYvRD3hg.js +1 -0
  161. package/webview-dist/chunks/gdshader-CBce3t8t.js +1 -0
  162. package/webview-dist/chunks/genie-CV2tkWYe.js +1 -0
  163. package/webview-dist/chunks/gherkin-DExj1W_8.js +1 -0
  164. package/webview-dist/chunks/git-commit-BSykSTBG.js +1 -0
  165. package/webview-dist/chunks/git-rebase-BBii7GBM.js +1 -0
  166. package/webview-dist/chunks/github-dark-C-LZuMrd.js +1 -0
  167. package/webview-dist/chunks/github-dark-default-DXG-b-1a.js +1 -0
  168. package/webview-dist/chunks/github-dark-dimmed-Bx1FflLF.js +1 -0
  169. package/webview-dist/chunks/github-dark-high-contrast-B_tTalzw.js +1 -0
  170. package/webview-dist/chunks/github-light-EUqPIrTm.js +1 -0
  171. package/webview-dist/chunks/github-light-default-BXViO-2h.js +1 -0
  172. package/webview-dist/chunks/github-light-high-contrast-B68TUdTA.js +1 -0
  173. package/webview-dist/chunks/gleam-CSRkHgEL.js +1 -0
  174. package/webview-dist/chunks/glimmer-js-CuCPna-X.js +1 -0
  175. package/webview-dist/chunks/glimmer-ts-DNAjZNDK.js +1 -0
  176. package/webview-dist/chunks/glsl-COQvRxdz.js +1 -0
  177. package/webview-dist/chunks/gn-ilITqXS6.js +1 -0
  178. package/webview-dist/chunks/gnuplot-7GGW24-e.js +1 -0
  179. package/webview-dist/chunks/go-rLFTqkRN.js +1 -0
  180. package/webview-dist/chunks/graphql-1cKCVreZ.js +1 -0
  181. package/webview-dist/chunks/groovy-CacY0gHj.js +1 -0
  182. package/webview-dist/chunks/gruvbox-dark-hard-C820rvS2.js +1 -0
  183. package/webview-dist/chunks/gruvbox-dark-medium-BPjhmG05.js +1 -0
  184. package/webview-dist/chunks/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  185. package/webview-dist/chunks/gruvbox-light-hard-BC_s9l72.js +1 -0
  186. package/webview-dist/chunks/gruvbox-light-medium-BAWPOn9u.js +1 -0
  187. package/webview-dist/chunks/gruvbox-light-soft-BSMLrYjP.js +1 -0
  188. package/webview-dist/chunks/hack-7CXYxWGO.js +1 -0
  189. package/webview-dist/chunks/haml-CeE16iG9.js +1 -0
  190. package/webview-dist/chunks/handlebars-CLm7Miue.js +1 -0
  191. package/webview-dist/chunks/haskell-D8IpX4py.js +1 -0
  192. package/webview-dist/chunks/haxe-C8oCnwJJ.js +1 -0
  193. package/webview-dist/chunks/hcl-Dh228itO.js +1 -0
  194. package/webview-dist/chunks/hjson-CxZEssPk.js +1 -0
  195. package/webview-dist/chunks/hlsl-Cvrh5tZx.js +1 -0
  196. package/webview-dist/chunks/horizon-CE9ld1lL.js +1 -0
  197. package/webview-dist/chunks/horizon-bright-DSNQnXHK.js +1 -0
  198. package/webview-dist/chunks/houston-CsvMBhTu.js +1 -0
  199. package/webview-dist/chunks/html-EbCri-_j.js +1 -0
  200. package/webview-dist/chunks/html-derivative-DGcE2kQi.js +1 -0
  201. package/webview-dist/chunks/http-DpnqgCg2.js +1 -0
  202. package/webview-dist/chunks/hurl-B6NGpamo.js +1 -0
  203. package/webview-dist/chunks/hxml-Dcm88srW.js +1 -0
  204. package/webview-dist/chunks/hy-CZbG8q4J.js +1 -0
  205. package/webview-dist/chunks/imba-DsUTQ-LC.js +1 -0
  206. package/webview-dist/chunks/ini-B5eOa1yu.js +1 -0
  207. package/webview-dist/chunks/java-ZkUoUSJy.js +1 -0
  208. package/webview-dist/chunks/javascript-DLd0EIw7.js +1 -0
  209. package/webview-dist/chunks/jinja-WhIqNp3q.js +1 -0
  210. package/webview-dist/chunks/jison-CIn1t7S8.js +1 -0
  211. package/webview-dist/chunks/json-AHG_JuKN.js +1 -0
  212. package/webview-dist/chunks/json5-BR5RXkoi.js +1 -0
  213. package/webview-dist/chunks/jsonc-CYpm1nAK.js +1 -0
  214. package/webview-dist/chunks/jsonl-CmCQp5Yx.js +1 -0
  215. package/webview-dist/chunks/jsonnet-CJTPZ8u_.js +1 -0
  216. package/webview-dist/chunks/jssm-DXw9l8Rf.js +1 -0
  217. package/webview-dist/chunks/jsx-BLy2KGb2.js +1 -0
  218. package/webview-dist/chunks/julia-XrhdGMY0.js +1 -0
  219. package/webview-dist/chunks/just-CiO9rOBq.js +1 -0
  220. package/webview-dist/chunks/kanagawa-dragon-Bozd7klA.js +1 -0
  221. package/webview-dist/chunks/kanagawa-lotus-BmuOG9ZW.js +1 -0
  222. package/webview-dist/chunks/kanagawa-wave-BML5mF2J.js +1 -0
  223. package/webview-dist/chunks/kdl-CsD5j6eV.js +1 -0
  224. package/webview-dist/chunks/kotlin-DhhofPvG.js +1 -0
  225. package/webview-dist/chunks/kusto-C7mF5XQf.js +1 -0
  226. package/webview-dist/chunks/laserwave-C_8bwKvT.js +1 -0
  227. package/webview-dist/chunks/latex-4tqdYtbu.js +1 -0
  228. package/webview-dist/chunks/lean-CewbzKMR.js +1 -0
  229. package/webview-dist/chunks/less-DVTAwKKz.js +1 -0
  230. package/webview-dist/chunks/light-plus-DVQuIRkW.js +1 -0
  231. package/webview-dist/chunks/liquid-BiiWRCLG.js +1 -0
  232. package/webview-dist/chunks/llvm-DqHOMS-s.js +1 -0
  233. package/webview-dist/chunks/log-BNLmms1o.js +1 -0
  234. package/webview-dist/chunks/logo-Cluzi2Zq.js +1 -0
  235. package/webview-dist/chunks/lua-BPFdS2Mc.js +1 -0
  236. package/webview-dist/chunks/luau-C2pBCSgt.js +1 -0
  237. package/webview-dist/chunks/make-Dixweg8N.js +1 -0
  238. package/webview-dist/chunks/markdown-BYOwaDjH.js +1 -0
  239. package/webview-dist/chunks/marko-BLi1Yy1V.js +1 -0
  240. package/webview-dist/chunks/material-theme-Bm3Qr25_.js +1 -0
  241. package/webview-dist/chunks/material-theme-darker-2IIEA8gg.js +1 -0
  242. package/webview-dist/chunks/material-theme-lighter-uhdI0v04.js +1 -0
  243. package/webview-dist/chunks/material-theme-ocean-CHQ94UKr.js +1 -0
  244. package/webview-dist/chunks/material-theme-palenight-B5W6OYN7.js +1 -0
  245. package/webview-dist/chunks/matlab-D7qyCx1q.js +1 -0
  246. package/webview-dist/chunks/mdc-Dx-qyM1x.js +1 -0
  247. package/webview-dist/chunks/mdx-DQZ5AkYe.js +1 -0
  248. package/webview-dist/chunks/mermaid-BxpfTIzt.js +1 -0
  249. package/webview-dist/chunks/min-dark-BSWPekZh.js +1 -0
  250. package/webview-dist/chunks/min-light-DDpmG2fV.js +1 -0
  251. package/webview-dist/chunks/mipsasm-BMqwQI7S.js +1 -0
  252. package/webview-dist/chunks/mojo-fg40_ntQ.js +1 -0
  253. package/webview-dist/chunks/monokai-B_bV9PQ9.js +1 -0
  254. package/webview-dist/chunks/moonbit-DgjMoLWr.js +1 -0
  255. package/webview-dist/chunks/move-BYnGhZoM.js +1 -0
  256. package/webview-dist/chunks/narrat-_X_XdTYD.js +1 -0
  257. package/webview-dist/chunks/nextflow-BJtWHP5T.js +1 -0
  258. package/webview-dist/chunks/nextflow-groovy-DJMQeKeT.js +1 -0
  259. package/webview-dist/chunks/nginx-rnpjAIVq.js +1 -0
  260. package/webview-dist/chunks/night-owl-DhmEMT88.js +1 -0
  261. package/webview-dist/chunks/night-owl-light-eJ-hLW7d.js +1 -0
  262. package/webview-dist/chunks/nim-kKTJ2fIs.js +1 -0
  263. package/webview-dist/chunks/nix-IvuFDN5E.js +1 -0
  264. package/webview-dist/chunks/nord-Cb4Vim4T.js +1 -0
  265. package/webview-dist/chunks/nsis-CjNLYCLg.js +1 -0
  266. package/webview-dist/chunks/nushell-DHYfO66s.js +1 -0
  267. package/webview-dist/chunks/objective-c-D1A_Heim.js +1 -0
  268. package/webview-dist/chunks/objective-cpp-BsSzOQcm.js +1 -0
  269. package/webview-dist/chunks/ocaml-O90oeIOV.js +1 -0
  270. package/webview-dist/chunks/odin-B1RWQWA5.js +1 -0
  271. package/webview-dist/chunks/one-dark-pro-CLwyXe_n.js +1 -0
  272. package/webview-dist/chunks/one-light-D7Lr4KcI.js +1 -0
  273. package/webview-dist/chunks/openscad-BUDT5pXO.js +1 -0
  274. package/webview-dist/chunks/org-BGWCjkJX.js +1 -0
  275. package/webview-dist/chunks/pascal-4ZHwLPI5.js +1 -0
  276. package/webview-dist/chunks/perl-DEimDILQ.js +1 -0
  277. package/webview-dist/chunks/php-QnaNN--1.js +1 -0
  278. package/webview-dist/chunks/pierre-dark-CpLgRqie.js +1 -0
  279. package/webview-dist/chunks/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
  280. package/webview-dist/chunks/pierre-dark-soft-kZQmAZld.js +1 -0
  281. package/webview-dist/chunks/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
  282. package/webview-dist/chunks/pierre-dark-vibrant-CpQYzh95.js +1 -0
  283. package/webview-dist/chunks/pierre-light-CoaEpmwp.js +1 -0
  284. package/webview-dist/chunks/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
  285. package/webview-dist/chunks/pierre-light-soft-lWLdNTOI.js +1 -0
  286. package/webview-dist/chunks/pierre-light-tritanopia-CEbqgOJL.js +1 -0
  287. package/webview-dist/chunks/pierre-light-vibrant-D80Fkn33.js +1 -0
  288. package/webview-dist/chunks/pkl-ot-7Btpt.js +1 -0
  289. package/webview-dist/chunks/plastic-DQwYfKfQ.js +1 -0
  290. package/webview-dist/chunks/plsql-DGHpHOYJ.js +1 -0
  291. package/webview-dist/chunks/po-BiJDBrnU.js +1 -0
  292. package/webview-dist/chunks/poimandres-DRFjx7u4.js +1 -0
  293. package/webview-dist/chunks/polar-C7UOKdEL.js +1 -0
  294. package/webview-dist/chunks/postcss-BXeXVLqQ.js +1 -0
  295. package/webview-dist/chunks/powerquery-DNMTfnFr.js +1 -0
  296. package/webview-dist/chunks/powershell-CCSX75yM.js +1 -0
  297. package/webview-dist/chunks/prisma-DMgNhnYS.js +1 -0
  298. package/webview-dist/chunks/prolog-iXnhIJG7.js +1 -0
  299. package/webview-dist/chunks/proto-DB4EqR-F.js +1 -0
  300. package/webview-dist/chunks/pug-D5rsKmMX.js +1 -0
  301. package/webview-dist/chunks/puppet-CDv2pdJW.js +1 -0
  302. package/webview-dist/chunks/purescript-9MfHhQsQ.js +1 -0
  303. package/webview-dist/chunks/python-gzcpVVnB.js +1 -0
  304. package/webview-dist/chunks/qml-wvbZb8UE.js +1 -0
  305. package/webview-dist/chunks/qmldir-DCQb3MpD.js +1 -0
  306. package/webview-dist/chunks/qss-Fe1Jh2GI.js +1 -0
  307. package/webview-dist/chunks/r-BNyBFaU1.js +1 -0
  308. package/webview-dist/chunks/racket-DcIDlBhZ.js +1 -0
  309. package/webview-dist/chunks/raku-B3gFvitq.js +1 -0
  310. package/webview-dist/chunks/razor-bKaHS6Kz.js +1 -0
  311. package/webview-dist/chunks/rbs-C0MpOrj4.js +1 -0
  312. package/webview-dist/chunks/red-DX1BQOs8.js +1 -0
  313. package/webview-dist/chunks/reg-CRGYupPL.js +1 -0
  314. package/webview-dist/chunks/regexp-B-mZuWUh.js +1 -0
  315. package/webview-dist/chunks/rel-BtDbiS_P.js +1 -0
  316. package/webview-dist/chunks/riscv-Ckw8ddFX.js +1 -0
  317. package/webview-dist/chunks/ron-VUp2lXgN.js +1 -0
  318. package/webview-dist/chunks/rose-pine-aMsaMD1D.js +1 -0
  319. package/webview-dist/chunks/rose-pine-dawn-8PwUyIlP.js +1 -0
  320. package/webview-dist/chunks/rose-pine-moon-DO-qXg-I.js +1 -0
  321. package/webview-dist/chunks/rosmsg-CAekHB0j.js +1 -0
  322. package/webview-dist/chunks/rst-Qq8ybXHe.js +1 -0
  323. package/webview-dist/chunks/ruby-U659LEwU.js +1 -0
  324. package/webview-dist/chunks/rust-Cfkwpbl8.js +1 -0
  325. package/webview-dist/chunks/sas-C4NtLApe.js +1 -0
  326. package/webview-dist/chunks/sass-DXrisJhu.js +1 -0
  327. package/webview-dist/chunks/scala-BiFt_7mu.js +1 -0
  328. package/webview-dist/chunks/scheme-DQCgrYNe.js +1 -0
  329. package/webview-dist/chunks/scss-KAaA4sHk.js +1 -0
  330. package/webview-dist/chunks/sdbl-bTVj8UrX.js +1 -0
  331. package/webview-dist/chunks/shaderlab-TOUzSsQk.js +1 -0
  332. package/webview-dist/chunks/shellscript-_7bOVsRC.js +1 -0
  333. package/webview-dist/chunks/shellsession-Bs_5k0qk.js +1 -0
  334. package/webview-dist/chunks/slack-dark-DnToyrRv.js +1 -0
  335. package/webview-dist/chunks/slack-ochin-B2OO5cIa.js +1 -0
  336. package/webview-dist/chunks/smalltalk-BHpQb5nM.js +1 -0
  337. package/webview-dist/chunks/smithy-Dgaz7aur.js +1 -0
  338. package/webview-dist/chunks/snazzy-light-4G7pJPwS.js +1 -0
  339. package/webview-dist/chunks/solarized-dark-UdsmMDCL.js +1 -0
  340. package/webview-dist/chunks/solarized-light-C1IUL_tW.js +1 -0
  341. package/webview-dist/chunks/solidity-Bj7E1mRn.js +1 -0
  342. package/webview-dist/chunks/soy-C5iuoFCh.js +1 -0
  343. package/webview-dist/chunks/sparql-D_iOobhT.js +1 -0
  344. package/webview-dist/chunks/splunk-BC2Px7Mm.js +1 -0
  345. package/webview-dist/chunks/sql-JX305rZh.js +1 -0
  346. package/webview-dist/chunks/ssh-config-BgfXC-Er.js +1 -0
  347. package/webview-dist/chunks/stata-2Rtik3TV.js +1 -0
  348. package/webview-dist/chunks/stylus-B6D30XZt.js +1 -0
  349. package/webview-dist/chunks/surrealql-IvpiLAIH.js +1 -0
  350. package/webview-dist/chunks/svelte-DeZcV_1u.js +1 -0
  351. package/webview-dist/chunks/swift-CyEgAFGc.js +1 -0
  352. package/webview-dist/chunks/synthwave-84-nFMaYfgc.js +1 -0
  353. package/webview-dist/chunks/system-verilog-Dh5ihWbf.js +1 -0
  354. package/webview-dist/chunks/systemd-BxMlprV5.js +1 -0
  355. package/webview-dist/chunks/talonscript-CohzipZa.js +1 -0
  356. package/webview-dist/chunks/tasl-DMoTqEGO.js +1 -0
  357. package/webview-dist/chunks/tcl-CZd0xW_V.js +1 -0
  358. package/webview-dist/chunks/templ-CcwjPXJr.js +1 -0
  359. package/webview-dist/chunks/terraform-DswuEJGm.js +1 -0
  360. package/webview-dist/chunks/tex-CZYHgHl8.js +1 -0
  361. package/webview-dist/chunks/tokyo-night-oM2G3aXe.js +1 -0
  362. package/webview-dist/chunks/toml-CcmNWLt0.js +1 -0
  363. package/webview-dist/chunks/ts-tags-DPINfEO_.js +1 -0
  364. package/webview-dist/chunks/tsv-sltzmVWM.js +1 -0
  365. package/webview-dist/chunks/tsx-Dq7pSIyE.js +1 -0
  366. package/webview-dist/chunks/turtle-ByJddavk.js +1 -0
  367. package/webview-dist/chunks/twig-DFpC8yDL.js +1 -0
  368. package/webview-dist/chunks/typescript-CN-guYmK.js +1 -0
  369. package/webview-dist/chunks/typespec-BRdr0IET.js +1 -0
  370. package/webview-dist/chunks/typst-hgW4q6mN.js +1 -0
  371. package/webview-dist/chunks/v-DBj4K9d_.js +1 -0
  372. package/webview-dist/chunks/vala-zf12oZj6.js +1 -0
  373. package/webview-dist/chunks/vb-DOwzaHZ0.js +1 -0
  374. package/webview-dist/chunks/verilog-B2gwz-sJ.js +1 -0
  375. package/webview-dist/chunks/vesper-DdrHHSXu.js +1 -0
  376. package/webview-dist/chunks/vhdl-BroJfC0k.js +1 -0
  377. package/webview-dist/chunks/viml-DvXPmvsu.js +1 -0
  378. package/webview-dist/chunks/vitesse-black-fwtXNY1n.js +1 -0
  379. package/webview-dist/chunks/vitesse-dark-BZCL-v6S.js +1 -0
  380. package/webview-dist/chunks/vitesse-light-VbXTXTou.js +1 -0
  381. package/webview-dist/chunks/vue-Dkz9ntel.js +1 -0
  382. package/webview-dist/chunks/vue-html-Dg8LQ5v3.js +1 -0
  383. package/webview-dist/chunks/vue-vine-CIEXICEN.js +1 -0
  384. package/webview-dist/chunks/vyper-CgoNMtux.js +1 -0
  385. package/webview-dist/chunks/wasm-BnjxR4X6.js +1 -0
  386. package/webview-dist/chunks/wasm-ByWQv1Qj.js +1 -0
  387. package/webview-dist/chunks/wenyan-C8pVoKbM.js +1 -0
  388. package/webview-dist/chunks/wgsl-BsKzXJz4.js +1 -0
  389. package/webview-dist/chunks/wikitext-ClFFjSW2.js +1 -0
  390. package/webview-dist/chunks/wit-DdvCle-K.js +1 -0
  391. package/webview-dist/chunks/wolfram-DLL8P-h_.js +1 -0
  392. package/webview-dist/chunks/worker-D52zl71O.js +1 -0
  393. package/webview-dist/chunks/worker-pool-lOjh8Q2A.js +1543 -0
  394. package/webview-dist/chunks/xml-X7YOen_c.js +1 -0
  395. package/webview-dist/chunks/xsl-h4d_Px-X.js +1 -0
  396. package/webview-dist/chunks/yaml-BRDpsfaj.js +1 -0
  397. package/webview-dist/chunks/zenscript-BnlCZFoB.js +1 -0
  398. package/webview-dist/chunks/zig-CMLA9XwU.js +1 -0
  399. package/webview-dist/index.html +18 -0
  400. package/webview-dist/pierre-worker-portable.js +13633 -0
  401. package/webview-dist/repo-timeline-app.js +7 -0
  402. package/webview-dist/repo-timeline.html +14 -0
  403. package/webview-dist/timeline-app.css +2 -0
  404. package/webview-dist/timeline-app.js +85 -0
@@ -0,0 +1,1154 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
+ require("./constants.cjs");
3
+ const require_blame = require("../shared/blame.cjs");
4
+ const require_history_adapters = require("./history-adapters.cjs");
5
+ const require_line_history = require("../shared/line-history.cjs");
6
+ const require_non_textual_details = require("../shared/non-textual-details.cjs");
7
+ const require_diff_stats = require("../shared/diff-stats.cjs");
8
+ const require_history_search = require("../shared/history-search.cjs");
9
+ const require_file_oplog = require("../shared/file-oplog.cjs");
10
+ let node_path = require("node:path");
11
+ node_path = require_runtime.__toESM(node_path, 1);
12
+ let node_fs_promises = require("node:fs/promises");
13
+ //#region src/extension/timeline-service.ts
14
+ const DEFAULT_TIMELINE_PREFERENCES = {
15
+ sidebarWidth: 276,
16
+ sidebarCollapsed: false,
17
+ timelinePaneHeight: 220,
18
+ timelinePaneCollapsed: false,
19
+ layoutMode: "split",
20
+ contentMode: "diffs",
21
+ comparisonMode: "range",
22
+ comparisonSource: "revision",
23
+ showIntermediateRevisions: false,
24
+ preset: "year",
25
+ customRevset: "",
26
+ themePreference: "auto",
27
+ heatmapOpen: false,
28
+ lineDiffType: "word-alt"
29
+ };
30
+ const IGNORED_WORKSPACE_DIRECTORIES = /* @__PURE__ */ new Set([
31
+ ".git",
32
+ ".jj",
33
+ "node_modules",
34
+ "dist",
35
+ "build",
36
+ "out",
37
+ "coverage"
38
+ ]);
39
+ function getComparisonEntries(request) {
40
+ const normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));
41
+ const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));
42
+ const fromEntry = request.entries[normalizedFromIndex];
43
+ const toEntry = request.entries[normalizedToIndex];
44
+ if (!fromEntry || !toEntry) return;
45
+ return {
46
+ fromEntry,
47
+ toEntry
48
+ };
49
+ }
50
+ function syncSession(request) {
51
+ request.target.adapter = request.source.adapter;
52
+ request.target.backend = request.source.backend;
53
+ request.target.workspacePath = request.source.workspacePath;
54
+ request.target.relativePath = request.source.relativePath;
55
+ request.target.absolutePath = request.source.absolutePath;
56
+ request.target.fileName = request.source.fileName;
57
+ request.target.entries = request.source.entries;
58
+ request.target.snapshotEntries = request.source.snapshotEntries;
59
+ request.target.snapshotLoadedChangeIds = request.source.snapshotLoadedChangeIds;
60
+ request.target.snapshotPendingChangeIds = request.source.snapshotPendingChangeIds;
61
+ request.target.workspaceFiles = request.source.workspaceFiles;
62
+ request.target.workspaceFilesLoaded = request.source.workspaceFilesLoaded;
63
+ request.target.historyLimit = request.source.historyLimit;
64
+ request.target.intermediateRevisionsLoaded = request.source.intermediateRevisionsLoaded;
65
+ request.target.contentCache = request.source.contentCache;
66
+ request.target.previewCache = request.source.previewCache;
67
+ request.target.rangeOverviewCache = request.source.rangeOverviewCache;
68
+ request.target.entryDiffCountCache = request.source.entryDiffCountCache;
69
+ request.target.pathCache = request.source.pathCache;
70
+ request.target.activeActionAbortController = request.source.activeActionAbortController;
71
+ request.target.lineHistory = request.source.lineHistory;
72
+ request.target.customRevset = request.source.customRevset;
73
+ }
74
+ async function getContentForRevset(request) {
75
+ const cacheKey = `revset:${request.revset}:${request.filePath}`;
76
+ const cached = request.session.contentCache.get(cacheKey);
77
+ if (cached !== void 0) return cached;
78
+ const content = await request.session.adapter.showFileAtRevision({
79
+ workspacePath: request.session.workspacePath,
80
+ revset: request.revset,
81
+ filePath: request.filePath
82
+ });
83
+ request.session.contentCache.set(cacheKey, content);
84
+ return content;
85
+ }
86
+ async function filterSessionEntriesForLineHistory(args) {
87
+ if (args.adapter.backend === "git") try {
88
+ const { stdout } = await args.runner.runGit({
89
+ workspacePath: args.workspacePath,
90
+ args: require_line_history.buildGitLineHistoryArgs({
91
+ relativePath: args.relativePath,
92
+ range: args.range,
93
+ limit: args.limit
94
+ })
95
+ });
96
+ const revisions = new Set(require_line_history.parseGitLineHistoryRevisions(stdout));
97
+ const filtered = args.entries.filter((entry) => entry.isWorkingTree || revisions.has(entry.revision));
98
+ if (filtered.length) return filtered;
99
+ } catch {}
100
+ const contentByRevision = /* @__PURE__ */ new Map();
101
+ for (const entry of args.entries) {
102
+ const filePath = entry.filePath || args.relativePath;
103
+ const revset = entry.isWorkingTree ? "@" : entry.revision;
104
+ try {
105
+ const content = await args.adapter.showFileAtRevision({
106
+ workspacePath: args.workspacePath,
107
+ revset: entry.isWorkingTree && args.adapter.backend === "git" ? "HEAD" : revset,
108
+ filePath
109
+ });
110
+ contentByRevision.set(entry.revision, content);
111
+ } catch {
112
+ contentByRevision.set(entry.revision, "");
113
+ }
114
+ }
115
+ if (args.adapter.backend === "git") {
116
+ const tip = args.entries.find((entry) => entry.isWorkingTree);
117
+ if (tip) try {
118
+ const diskPath = node_path.default.join(args.workspacePath, tip.filePath || args.relativePath);
119
+ contentByRevision.set(tip.revision, await (0, node_fs_promises.readFile)(diskPath, "utf8"));
120
+ } catch {}
121
+ }
122
+ return require_line_history.filterEntriesTouchingLineRange({
123
+ entries: args.entries,
124
+ range: args.range,
125
+ getContent: (entry) => contentByRevision.get(entry.revision) || ""
126
+ });
127
+ }
128
+ async function hydrateEntryFilePaths(args) {
129
+ if (!args.entries.length) return;
130
+ args.entries[args.entries.length - 1].filePath = args.relativePath;
131
+ let currentPath = args.relativePath;
132
+ for (let index = args.entries.length - 1; index > 0; index -= 1) {
133
+ const currentEntry = args.entries[index];
134
+ const previousEntry = args.entries[index - 1];
135
+ if (previousEntry.filePath) {
136
+ currentPath = previousEntry.filePath;
137
+ continue;
138
+ }
139
+ let previousPath = currentPath;
140
+ if (currentEntry.touchesFile && !currentEntry.isWorkingTree) previousPath = await args.adapter.resolvePreviousPath({
141
+ workspacePath: args.workspacePath,
142
+ revision: currentEntry.revision,
143
+ currentPath
144
+ });
145
+ previousEntry.filePath = previousPath;
146
+ currentPath = previousPath;
147
+ }
148
+ }
149
+ async function resolvePreviousPathAcrossRevision(request) {
150
+ const cacheKey = `${request.entry.revision}:${request.currentPath}`;
151
+ const cached = request.session.pathCache.get(cacheKey);
152
+ if (cached) return cached;
153
+ const previousPath = await request.session.adapter.resolvePreviousPath({
154
+ workspacePath: request.session.workspacePath,
155
+ revision: request.entry.revision,
156
+ currentPath: request.currentPath
157
+ });
158
+ request.session.pathCache.set(cacheKey, previousPath);
159
+ return previousPath;
160
+ }
161
+ async function loadRevisionTreeFiles(request) {
162
+ const revision = request.revision.trim() || "@";
163
+ try {
164
+ return await request.session.adapter.listRevisionTreeFiles({
165
+ workspacePath: request.session.workspacePath,
166
+ revision
167
+ });
168
+ } catch {
169
+ return [];
170
+ }
171
+ }
172
+ function createTimelineService(args) {
173
+ const { runner } = args;
174
+ return {
175
+ buildSession,
176
+ buildPayload,
177
+ mapEntriesForPayload,
178
+ ensureWorkspaceFiles,
179
+ loadRevisionTreeFiles,
180
+ ensureIntermediateRevisions,
181
+ expandFileHistory,
182
+ findNearestNonEmptyVisibleRange,
183
+ getComparisonEntries,
184
+ getDiffPreview,
185
+ getDiffBlame,
186
+ getFileOpLog,
187
+ searchFileHistory,
188
+ getEntryDiffCounts,
189
+ getEntriesForSource,
190
+ getRangeOverview,
191
+ getRangeStackPreviews,
192
+ hydrateSnapshotEntries,
193
+ resolveBlameRevisionForLine,
194
+ runSessionAction,
195
+ resolveEntryFilePath,
196
+ syncSession
197
+ };
198
+ async function buildSession(request) {
199
+ const historyWorkspacePath = await require_history_adapters.resolveHistoryWorkspacePath({
200
+ workspacePath: request.workspacePath,
201
+ runner
202
+ });
203
+ const relativePath = node_path.default.relative(historyWorkspacePath, request.absolutePath).replace(/\\/g, "/");
204
+ const adapter = await require_history_adapters.resolveHistoryAdapter({
205
+ workspacePath: historyWorkspacePath,
206
+ runner
207
+ });
208
+ const entryLimit = request.options?.entryLimit ?? 50;
209
+ const includeWorkspaceFiles = request.options?.includeWorkspaceFiles === true;
210
+ const includeIntermediateRevisions = request.options?.includeIntermediateRevisions === true;
211
+ const lineHistory = request.options?.lineHistory ? require_line_history.normalizeLineHistoryRange(request.options.lineHistory.startLine, request.options.lineHistory.endLine) : null;
212
+ const customRevset = (request.options?.customRevset || "").trim() || void 0;
213
+ const workspaceFiles = includeWorkspaceFiles ? await listWorkspaceFiles({
214
+ adapter,
215
+ workspacePath: historyWorkspacePath
216
+ }) : [relativePath];
217
+ const fileEntries = await adapter.getFileRevisionHistory({
218
+ workspacePath: historyWorkspacePath,
219
+ relativePath,
220
+ limit: entryLimit,
221
+ customRevset
222
+ });
223
+ let entries = await buildTimelineEntries({
224
+ adapter,
225
+ workspacePath: historyWorkspacePath,
226
+ absolutePath: request.absolutePath,
227
+ relativePath,
228
+ fileEntries,
229
+ includeIntermediateRevisions,
230
+ entryLimit
231
+ });
232
+ if (lineHistory) entries = await filterSessionEntriesForLineHistory({
233
+ adapter,
234
+ runner,
235
+ workspacePath: historyWorkspacePath,
236
+ relativePath,
237
+ entries,
238
+ range: lineHistory,
239
+ limit: entryLimit
240
+ });
241
+ const snapshotEntries = adapter.backend === "jj" ? [] : [...entries];
242
+ const remoteBaseUrl = await adapter.getRemoteBaseUrl({ workspacePath: historyWorkspacePath });
243
+ if (remoteBaseUrl) {
244
+ for (const entry of entries) if (!entry.isWorkingTree) entry.remoteUrl = `${remoteBaseUrl}/commit/${entry.revision}`;
245
+ }
246
+ await hydrateEntryFilePaths({
247
+ adapter,
248
+ workspacePath: historyWorkspacePath,
249
+ relativePath,
250
+ entries
251
+ });
252
+ return {
253
+ adapter,
254
+ backend: adapter.backend,
255
+ workspacePath: historyWorkspacePath,
256
+ absolutePath: request.absolutePath,
257
+ relativePath,
258
+ fileName: node_path.default.basename(request.absolutePath),
259
+ entries,
260
+ snapshotEntries,
261
+ snapshotLoadedChangeIds: /* @__PURE__ */ new Set(),
262
+ snapshotPendingChangeIds: /* @__PURE__ */ new Set(),
263
+ workspaceFiles,
264
+ workspaceFilesLoaded: includeWorkspaceFiles,
265
+ historyLimit: entryLimit,
266
+ intermediateRevisionsLoaded: includeIntermediateRevisions,
267
+ lineHistory: lineHistory ?? void 0,
268
+ customRevset,
269
+ contentCache: /* @__PURE__ */ new Map(),
270
+ previewCache: /* @__PURE__ */ new Map(),
271
+ rangeOverviewCache: /* @__PURE__ */ new Map(),
272
+ entryDiffCountCache: /* @__PURE__ */ new Map(),
273
+ pathCache: /* @__PURE__ */ new Map(),
274
+ activeActionAbortController: void 0
275
+ };
276
+ }
277
+ function mapEntriesForPayload(entries) {
278
+ return entries.map((entry, index) => ({
279
+ ...entry,
280
+ index,
281
+ hasPreviousEntry: index > 0,
282
+ monthLabel: formatEntryMonthLabel(entry.authorDate),
283
+ shortDate: formatEntryShortDate(entry.authorDate),
284
+ relativeDate: formatRelativeTime(entry.timestamp)
285
+ }));
286
+ }
287
+ function buildPayload(request) {
288
+ return {
289
+ backend: request.session.backend,
290
+ workspacePath: request.session.workspacePath,
291
+ relativePath: request.session.relativePath,
292
+ fileName: request.session.fileName,
293
+ version: request.version,
294
+ presets: request.presets,
295
+ defaultIndex: Math.max(0, request.session.entries.length - 1),
296
+ latestIndex: Math.max(0, request.session.entries.length - 1),
297
+ preferences: normalizeTimelinePreferences(request.preferences),
298
+ workspaceFiles: request.session.workspaceFiles,
299
+ workspaceFilesLoaded: request.session.workspaceFilesLoaded,
300
+ hasIntermediateRevisions: request.session.entries.some((entry) => !entry.touchesFile),
301
+ entries: mapEntriesForPayload(request.session.entries),
302
+ snapshotEntries: mapEntriesForPayload(request.session.snapshotEntries),
303
+ snapshotState: { loadedChangeIds: [...request.session.snapshotLoadedChangeIds] },
304
+ ...request.session.lineHistory ? { lineHistory: request.session.lineHistory } : {},
305
+ ...request.session.customRevset ? { customRevset: request.session.customRevset } : {}
306
+ };
307
+ }
308
+ async function ensureWorkspaceFiles(request) {
309
+ if (request.session.workspaceFilesLoaded) return false;
310
+ const workspaceFiles = await listWorkspaceFiles({
311
+ adapter: request.session.adapter,
312
+ workspacePath: request.session.workspacePath
313
+ });
314
+ request.session.workspaceFiles = workspaceFiles;
315
+ request.session.workspaceFilesLoaded = true;
316
+ request.session.rangeOverviewCache.clear();
317
+ return true;
318
+ }
319
+ async function ensureIntermediateRevisions(request) {
320
+ if (request.session.intermediateRevisionsLoaded) return false;
321
+ const touchingEntries = request.session.entries.filter((entry) => entry.touchesFile && !entry.isWorkingTree);
322
+ if (touchingEntries.length < 2) {
323
+ request.session.intermediateRevisionsLoaded = true;
324
+ return false;
325
+ }
326
+ try {
327
+ const repositoryEntries = await request.session.adapter.getRepositoryRevisionHistory({
328
+ workspacePath: request.session.workspacePath,
329
+ limit: 200
330
+ });
331
+ const workingTreeEntry = request.session.entries.find((entry) => entry.isWorkingTree);
332
+ let entries = mergeTimelineEntries({
333
+ repositoryEntries,
334
+ fileEntries: touchingEntries
335
+ });
336
+ if (request.session.backend === "jj") entries = dedupeAdjacentTimelineEntries(entries);
337
+ if (workingTreeEntry) entries = [...entries, workingTreeEntry];
338
+ request.session.entries = entries;
339
+ request.session.intermediateRevisionsLoaded = true;
340
+ request.session.previewCache.clear();
341
+ request.session.rangeOverviewCache.clear();
342
+ request.session.entryDiffCountCache.clear();
343
+ return true;
344
+ } catch {
345
+ request.session.intermediateRevisionsLoaded = true;
346
+ return false;
347
+ }
348
+ }
349
+ async function expandFileHistory(request) {
350
+ if (request.session.historyLimit >= 200) return false;
351
+ const previousTouchingCount = request.session.entries.filter((entry) => entry.touchesFile && !entry.isWorkingTree).length;
352
+ if (previousTouchingCount < request.session.historyLimit) {
353
+ request.session.historyLimit = 200;
354
+ return false;
355
+ }
356
+ const fileEntries = await request.session.adapter.getFileRevisionHistory({
357
+ workspacePath: request.session.workspacePath,
358
+ relativePath: request.session.relativePath,
359
+ limit: 200
360
+ });
361
+ const entries = await buildTimelineEntries({
362
+ adapter: request.session.adapter,
363
+ workspacePath: request.session.workspacePath,
364
+ absolutePath: request.session.absolutePath,
365
+ relativePath: request.session.relativePath,
366
+ fileEntries,
367
+ includeIntermediateRevisions: request.session.intermediateRevisionsLoaded,
368
+ entryLimit: 200
369
+ });
370
+ const nextTouchingCount = entries.filter((entry) => entry.touchesFile && !entry.isWorkingTree).length;
371
+ request.session.entries = entries;
372
+ request.session.historyLimit = 200;
373
+ request.session.previewCache.clear();
374
+ request.session.rangeOverviewCache.clear();
375
+ request.session.entryDiffCountCache.clear();
376
+ return nextTouchingCount > previousTouchingCount;
377
+ }
378
+ function getEntriesForSource(request) {
379
+ if (request.session.backend !== "jj" || request.comparisonSource !== "snapshot") return request.session.entries;
380
+ return composeSnapshotEntries({
381
+ revisionEntries: request.session.entries,
382
+ snapshotEntries: request.session.snapshotEntries,
383
+ loadedChangeIds: request.session.snapshotLoadedChangeIds
384
+ });
385
+ }
386
+ async function getDiffPreview(request) {
387
+ const comparisonSource = request.comparisonSource || "revision";
388
+ const sourceEntries = getEntriesForSource({
389
+ session: request.session,
390
+ comparisonSource
391
+ });
392
+ const normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));
393
+ const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));
394
+ const cacheKey = `${comparisonSource}:${normalizedFromIndex}:${normalizedToIndex}`;
395
+ const cached = request.session.previewCache.get(cacheKey);
396
+ if (cached) return cached;
397
+ if (request.session.backend === "jj" && comparisonSource === "snapshot") {
398
+ const preview = await getJjSnapshotPreview({
399
+ session: request.session,
400
+ fromIndex: normalizedFromIndex,
401
+ toIndex: normalizedToIndex
402
+ });
403
+ request.session.previewCache.set(cacheKey, preview);
404
+ return preview;
405
+ }
406
+ const comparison = getComparisonEntries({
407
+ entries: sourceEntries,
408
+ fromIndex: normalizedFromIndex,
409
+ toIndex: normalizedToIndex
410
+ });
411
+ if (!comparison) return createEmptyPreview({
412
+ index: normalizedToIndex,
413
+ fromIndex: normalizedFromIndex,
414
+ toIndex: normalizedToIndex,
415
+ comparisonSource,
416
+ title: "No revision selected"
417
+ });
418
+ const beforePath = comparison.fromEntry ? await resolveEntryFilePath({
419
+ session: request.session,
420
+ entry: comparison.fromEntry,
421
+ entryIndex: normalizedFromIndex
422
+ }) : "";
423
+ const afterPath = await resolveEntryFilePath({
424
+ session: request.session,
425
+ entry: comparison.toEntry,
426
+ entryIndex: normalizedToIndex
427
+ });
428
+ const beforeText = comparison.fromEntry ? await getRevisionContent({
429
+ session: request.session,
430
+ entry: comparison.fromEntry,
431
+ entryIndex: normalizedFromIndex
432
+ }) : "";
433
+ const afterText = await getRevisionContent({
434
+ session: request.session,
435
+ entry: comparison.toEntry,
436
+ entryIndex: normalizedToIndex
437
+ });
438
+ const preview = buildDiffPreview({
439
+ index: normalizedToIndex,
440
+ previousEntry: comparison.fromEntry,
441
+ currentEntry: comparison.toEntry,
442
+ beforeText,
443
+ afterText,
444
+ fromIndex: normalizedFromIndex,
445
+ toIndex: normalizedToIndex,
446
+ beforePath,
447
+ afterPath,
448
+ comparisonSource
449
+ });
450
+ request.session.previewCache.set(cacheKey, preview);
451
+ return preview;
452
+ }
453
+ async function hydrateSnapshotEntries(request) {
454
+ if (request.session.backend !== "jj") return false;
455
+ const uniqueTargets = request.revisionIndexes.map((index) => request.session.entries[index]).filter((entry) => Boolean(entry && !entry.isWorkingTree && entry.touchesFile && entry.changeId && !request.session.snapshotLoadedChangeIds.has(entry.changeId) && !request.session.snapshotPendingChangeIds.has(entry.changeId))).reduce((entries, entry) => {
456
+ if (!entry.changeId || entries.some((candidate) => candidate.changeId === entry.changeId)) return entries;
457
+ entries.push(entry);
458
+ return entries;
459
+ }, []).slice(-8);
460
+ if (!uniqueTargets.length) return false;
461
+ let didUpdate = false;
462
+ for (const entry of uniqueTargets) {
463
+ const changeId = entry.changeId;
464
+ if (!changeId) continue;
465
+ request.session.snapshotPendingChangeIds.add(changeId);
466
+ const expandedEntries = await request.session.adapter.getSnapshotEntriesForFile({
467
+ workspacePath: request.session.workspacePath,
468
+ relativePath: request.session.relativePath,
469
+ entry
470
+ });
471
+ request.session.snapshotPendingChangeIds.delete(changeId);
472
+ request.session.snapshotLoadedChangeIds.add(changeId);
473
+ if (expandedEntries.length) {
474
+ request.session.snapshotEntries.push(...expandedEntries);
475
+ didUpdate = true;
476
+ }
477
+ }
478
+ if (!didUpdate) return true;
479
+ request.session.snapshotEntries = request.session.snapshotEntries.toSorted((left, right) => left.timestamp - right.timestamp || left.revision.localeCompare(right.revision));
480
+ for (const cacheKey of request.session.previewCache.keys()) if (cacheKey.startsWith("snapshot:")) request.session.previewCache.delete(cacheKey);
481
+ for (const cacheKey of request.session.rangeOverviewCache.keys()) if (cacheKey.startsWith("snapshot:")) request.session.rangeOverviewCache.delete(cacheKey);
482
+ for (const cacheKey of request.session.entryDiffCountCache.keys()) if (cacheKey.startsWith("snapshot:")) request.session.entryDiffCountCache.delete(cacheKey);
483
+ return true;
484
+ }
485
+ async function findNearestNonEmptyVisibleRange(request) {
486
+ if (request.candidateIndexes.length < 2) return null;
487
+ for (let index = request.candidateIndexes.length - 1; index > 0; index -= 1) {
488
+ const fromIndex = request.candidateIndexes[index - 1];
489
+ const toIndex = request.candidateIndexes[index];
490
+ if ((await getDiffPreview({
491
+ session: request.session,
492
+ fromIndex,
493
+ toIndex
494
+ })).hasChanges) return {
495
+ fromIndex,
496
+ toIndex
497
+ };
498
+ }
499
+ return null;
500
+ }
501
+ async function getRangeOverview(request) {
502
+ const comparisonSource = request.comparisonSource || "revision";
503
+ const normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));
504
+ const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));
505
+ const selectedEntryIndexes = (request.selectedEntryIndexes || []).filter((value) => Number.isInteger(value));
506
+ const cacheKey = `${comparisonSource}:${normalizedFromIndex}:${normalizedToIndex}:${selectedEntryIndexes.length ? selectedEntryIndexes.join(",") : "all"}`;
507
+ const cached = request.session.rangeOverviewCache.get(cacheKey);
508
+ if (cached) return cached;
509
+ const sourceEntries = getEntriesForSource({
510
+ session: request.session,
511
+ comparisonSource
512
+ });
513
+ const countedPaths = /* @__PURE__ */ new Map();
514
+ if (!request.session.workspaceFilesLoaded) await ensureWorkspaceFiles({ session: request.session });
515
+ const workspaceFileSet = new Set(request.session.workspaceFiles);
516
+ const entryIndexesToScan = selectedEntryIndexes.length ? selectedEntryIndexes : Array.from({ length: normalizedToIndex - normalizedFromIndex }, (_, index) => normalizedFromIndex + index + 1);
517
+ for (const index of entryIndexesToScan) {
518
+ const entry = sourceEntries[index];
519
+ if (!entry) continue;
520
+ const changedFiles = entry.isWorkingTree ? await request.session.adapter.listWorkingTreeFiles({ workspacePath: request.session.workspacePath }) : await request.session.adapter.listRevisionFiles({
521
+ workspacePath: request.session.workspacePath,
522
+ revision: entry.revision
523
+ });
524
+ for (const relativePath of changedFiles) {
525
+ if (!relativePath || !workspaceFileSet.has(relativePath) && relativePath !== request.session.relativePath) continue;
526
+ countedPaths.set(relativePath, (countedPaths.get(relativePath) || 0) + 1);
527
+ }
528
+ }
529
+ const items = [...countedPaths.entries()].map(([relativePath, changeCount]) => ({
530
+ relativePath,
531
+ changeCount,
532
+ isCurrentFile: relativePath === request.session.relativePath
533
+ })).toSorted((left, right) => {
534
+ if (left.changeCount !== right.changeCount) return right.changeCount - left.changeCount;
535
+ if (left.isCurrentFile !== right.isCurrentFile) return Number(right.isCurrentFile) - Number(left.isCurrentFile);
536
+ return left.relativePath.localeCompare(right.relativePath);
537
+ }).slice(0, 150);
538
+ request.session.rangeOverviewCache.set(cacheKey, items);
539
+ return items;
540
+ }
541
+ async function getRangeStackPreviews(request) {
542
+ const comparisonSource = request.comparisonSource || "revision";
543
+ const normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));
544
+ const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));
545
+ const comparison = getComparisonEntries({
546
+ entries: getEntriesForSource({
547
+ session: request.session,
548
+ comparisonSource
549
+ }),
550
+ fromIndex: normalizedFromIndex,
551
+ toIndex: normalizedToIndex
552
+ });
553
+ if (!comparison) return [];
554
+ const items = [];
555
+ for (const relativePath of request.relativePaths) {
556
+ const trimmed = relativePath.trim();
557
+ if (!trimmed) continue;
558
+ if (trimmed === request.session.relativePath) {
559
+ items.push({
560
+ relativePath: trimmed,
561
+ preview: await getDiffPreview({
562
+ session: request.session,
563
+ fromIndex: normalizedFromIndex,
564
+ toIndex: normalizedToIndex,
565
+ comparisonSource
566
+ })
567
+ });
568
+ continue;
569
+ }
570
+ const beforeText = comparison.fromEntry ? await readPathAtEntry({
571
+ session: request.session,
572
+ entry: comparison.fromEntry,
573
+ relativePath: trimmed
574
+ }) : "";
575
+ const afterText = await readPathAtEntry({
576
+ session: request.session,
577
+ entry: comparison.toEntry,
578
+ relativePath: trimmed
579
+ });
580
+ items.push({
581
+ relativePath: trimmed,
582
+ preview: buildDiffPreview({
583
+ index: normalizedToIndex,
584
+ previousEntry: comparison.fromEntry,
585
+ currentEntry: comparison.toEntry,
586
+ beforeText,
587
+ afterText,
588
+ fromIndex: normalizedFromIndex,
589
+ toIndex: normalizedToIndex,
590
+ beforePath: trimmed,
591
+ afterPath: trimmed,
592
+ comparisonSource
593
+ })
594
+ });
595
+ }
596
+ return items;
597
+ }
598
+ async function readPathAtEntry(request) {
599
+ const cacheKey = `${request.entry.id}:stack:${request.relativePath}`;
600
+ const cached = request.session.contentCache.get(cacheKey);
601
+ if (cached !== void 0) return cached;
602
+ try {
603
+ const content = request.entry.isWorkingTree ? await (0, node_fs_promises.readFile)(node_path.default.join(request.session.workspacePath, request.relativePath), "utf8") : await request.session.adapter.showFileAtRevision({
604
+ workspacePath: request.session.workspacePath,
605
+ revset: request.entry.revision,
606
+ filePath: request.relativePath
607
+ });
608
+ request.session.contentCache.set(cacheKey, content);
609
+ return content;
610
+ } catch {
611
+ request.session.contentCache.set(cacheKey, "");
612
+ return "";
613
+ }
614
+ }
615
+ async function getEntryDiffCounts(request) {
616
+ const comparisonSource = request.comparisonSource || "revision";
617
+ const sourceEntries = getEntriesForSource({
618
+ session: request.session,
619
+ comparisonSource
620
+ });
621
+ return Promise.all(request.entryIndexes.map(async (entryIndex) => {
622
+ const cacheKey = `${comparisonSource}:${entryIndex}`;
623
+ const cached = request.session.entryDiffCountCache.get(cacheKey);
624
+ if (cached !== void 0) return {
625
+ entryIndex,
626
+ diffCount: cached
627
+ };
628
+ const entry = sourceEntries[entryIndex];
629
+ if (!entry || entryIndex <= 0) {
630
+ request.session.entryDiffCountCache.set(cacheKey, 0);
631
+ return {
632
+ entryIndex,
633
+ diffCount: 0
634
+ };
635
+ }
636
+ let diffCount = 0;
637
+ if (entry.isWorkingTree) {
638
+ const previousEntry = sourceEntries[entryIndex - 1];
639
+ if (previousEntry) diffCount = (await request.session.adapter.buildRangeMultiDiffPlan({
640
+ workspacePath: request.session.workspacePath,
641
+ fromEntry: previousEntry,
642
+ toEntry: entry,
643
+ comparisonSource,
644
+ sourceEntries
645
+ })).files.length;
646
+ } else diffCount = (await request.session.adapter.buildRevisionMultiDiffPlan({
647
+ workspacePath: request.session.workspacePath,
648
+ entry,
649
+ entryIndex,
650
+ comparisonSource,
651
+ sourceEntries
652
+ })).files.length;
653
+ request.session.entryDiffCountCache.set(cacheKey, diffCount);
654
+ return {
655
+ entryIndex,
656
+ diffCount
657
+ };
658
+ }));
659
+ }
660
+ async function resolveEntryFilePath(request) {
661
+ if (request.entry.isWorkingTree) return request.session.relativePath;
662
+ if (request.entry.filePath) return request.entry.filePath;
663
+ await ensureEntryFilePath(request);
664
+ return request.entry.filePath || request.session.relativePath;
665
+ }
666
+ async function runSessionAction(request) {
667
+ request.session.activeActionAbortController?.abort();
668
+ const controller = new AbortController();
669
+ request.session.activeActionAbortController = controller;
670
+ try {
671
+ await request.action(controller.signal);
672
+ } catch (error) {
673
+ if (isAbortError(error) || controller.signal.aborted) return;
674
+ throw error;
675
+ } finally {
676
+ if (request.session.activeActionAbortController === controller) request.session.activeActionAbortController = void 0;
677
+ }
678
+ }
679
+ async function resolveBlameRevisionForLine(request) {
680
+ try {
681
+ if (request.backend === "git") {
682
+ const { stdout } = await runner.runGit({
683
+ workspacePath: request.workspacePath,
684
+ args: require_blame.buildGitBlameArgs({
685
+ relativePath: request.relativePath,
686
+ line: request.line
687
+ })
688
+ });
689
+ return require_blame.findBlameForLine(require_blame.parseGitBlamePorcelain(stdout), request.line)?.revision;
690
+ }
691
+ const { stdout } = await runner.runJj({
692
+ workspacePath: request.workspacePath,
693
+ args: require_blame.buildJjAnnotateArgs({ relativePath: request.relativePath })
694
+ });
695
+ return require_blame.findBlameForLine(require_blame.parseJjFileAnnotate(stdout), request.line)?.revision;
696
+ } catch {
697
+ return;
698
+ }
699
+ }
700
+ async function getDiffBlame(request) {
701
+ const comparisonSource = request.comparisonSource || "revision";
702
+ const normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));
703
+ const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));
704
+ const toEntry = getEntriesForSource({
705
+ session: request.session,
706
+ comparisonSource
707
+ })[normalizedToIndex];
708
+ const relativePath = toEntry?.filePath || request.session.relativePath;
709
+ if (!toEntry) return {
710
+ relativePath,
711
+ lines: []
712
+ };
713
+ try {
714
+ if (request.session.backend === "git") {
715
+ const { stdout } = await runner.runGit({
716
+ workspacePath: request.session.workspacePath,
717
+ args: require_blame.buildGitBlameFileArgs({
718
+ relativePath,
719
+ revision: toEntry.isWorkingTree ? void 0 : toEntry.revision
720
+ })
721
+ });
722
+ return {
723
+ relativePath,
724
+ lines: require_blame.parseGitBlamePorcelain(stdout)
725
+ };
726
+ }
727
+ const { stdout } = await runner.runJj({
728
+ workspacePath: request.session.workspacePath,
729
+ args: require_blame.buildJjAnnotateArgs({
730
+ relativePath,
731
+ revision: toEntry.isWorkingTree ? void 0 : toEntry.revision
732
+ })
733
+ });
734
+ return {
735
+ relativePath,
736
+ lines: require_blame.parseJjFileAnnotate(stdout)
737
+ };
738
+ } catch {
739
+ return {
740
+ relativePath,
741
+ lines: []
742
+ };
743
+ }
744
+ }
745
+ async function getFileOpLog(request) {
746
+ const relativePath = request.session.relativePath;
747
+ if (request.session.backend !== "jj") return {
748
+ relativePath,
749
+ entries: []
750
+ };
751
+ try {
752
+ const { stdout } = await runner.runJj({
753
+ workspacePath: request.session.workspacePath,
754
+ args: [
755
+ "op",
756
+ "log",
757
+ "--limit",
758
+ "80",
759
+ "-T",
760
+ require_file_oplog.JJ_OP_LOG_TEMPLATE
761
+ ]
762
+ });
763
+ const fileEntries = [...request.session.snapshotEntries, ...request.session.entries.filter((entry) => Boolean(entry.operationId))];
764
+ return {
765
+ relativePath,
766
+ entries: require_file_oplog.filterFileOpLogPeek({
767
+ opLog: require_file_oplog.parseJjOpLogOutput(stdout),
768
+ fileEntries,
769
+ relativePath,
770
+ limit: 12
771
+ })
772
+ };
773
+ } catch {
774
+ return {
775
+ relativePath,
776
+ entries: []
777
+ };
778
+ }
779
+ }
780
+ async function searchFileHistory(request) {
781
+ const maxEntries = request.maxEntries ?? 40;
782
+ const touching = request.session.entries.map((entry, index) => ({
783
+ entry,
784
+ index
785
+ })).filter(({ entry }) => entry.touchesFile && !entry.isWorkingTree).slice(-maxEntries);
786
+ const contentsByIndex = /* @__PURE__ */ new Map();
787
+ for (const { entry, index } of touching) try {
788
+ const content = await getRevisionContent({
789
+ session: request.session,
790
+ entry,
791
+ entryIndex: index
792
+ });
793
+ contentsByIndex.set(index, content);
794
+ } catch {
795
+ contentsByIndex.set(index, "");
796
+ }
797
+ const orderedEntryIndexes = touching.map(({ index }) => index);
798
+ if (request.purpose === "sidebar") return require_history_search.searchHistoryDiffContents({
799
+ query: request.query,
800
+ orderedEntryIndexes,
801
+ contentsByIndex
802
+ });
803
+ return require_history_search.searchHistoryContents({
804
+ query: request.query,
805
+ orderedEntryIndexes,
806
+ contentsByIndex
807
+ });
808
+ }
809
+ async function buildTimelineEntries(request) {
810
+ const touchingEntries = request.fileEntries.map((entry) => ({
811
+ ...entry,
812
+ touchesFile: true
813
+ }));
814
+ if (touchingEntries.length) touchingEntries[touchingEntries.length - 1].filePath = request.relativePath;
815
+ let entries = touchingEntries;
816
+ if (request.includeIntermediateRevisions && touchingEntries.length >= 2) try {
817
+ entries = mergeTimelineEntries({
818
+ repositoryEntries: await request.adapter.getRepositoryRevisionHistory({
819
+ workspacePath: request.workspacePath,
820
+ limit: Math.max(request.entryLimit, 200)
821
+ }),
822
+ fileEntries: touchingEntries
823
+ });
824
+ } catch {
825
+ entries = touchingEntries;
826
+ }
827
+ if (request.adapter.backend === "jj") entries = dedupeAdjacentTimelineEntries(entries);
828
+ return appendWorkingTreeEntry({
829
+ adapter: request.adapter,
830
+ workspacePath: request.workspacePath,
831
+ absolutePath: request.absolutePath,
832
+ relativePath: request.relativePath,
833
+ entries
834
+ });
835
+ }
836
+ async function listWorkspaceFiles(request) {
837
+ if (request.adapter.backend === "git") try {
838
+ const { stdout } = await runner.runGit({
839
+ workspacePath: request.workspacePath,
840
+ args: [
841
+ "ls-files",
842
+ "--cached",
843
+ "-z"
844
+ ]
845
+ });
846
+ const files = stdout.split("\0").map((value) => value.trim()).filter(Boolean).toSorted((left, right) => left.localeCompare(right));
847
+ if (files.length) return files;
848
+ } catch {}
849
+ if (request.adapter.backend === "jj") try {
850
+ const { stdout } = await runner.runJj({
851
+ workspacePath: request.workspacePath,
852
+ args: ["file", "list"]
853
+ });
854
+ const files = stdout.split(/\r?\n/u).map((value) => value.trim()).filter(Boolean).toSorted((left, right) => left.localeCompare(right));
855
+ if (files.length) return files;
856
+ } catch {}
857
+ const files = [];
858
+ await collectWorkspaceFiles({
859
+ workspacePath: request.workspacePath,
860
+ currentDirectory: request.workspacePath,
861
+ files
862
+ });
863
+ return files.toSorted((left, right) => left.localeCompare(right));
864
+ }
865
+ async function collectWorkspaceFiles(request) {
866
+ const directoryEntries = await (0, node_fs_promises.readdir)(request.currentDirectory, { withFileTypes: true });
867
+ for (const directoryEntry of directoryEntries) {
868
+ if (directoryEntry.isDirectory() && IGNORED_WORKSPACE_DIRECTORIES.has(directoryEntry.name)) continue;
869
+ const absolutePath = node_path.default.join(request.currentDirectory, directoryEntry.name);
870
+ if (directoryEntry.isDirectory()) {
871
+ await collectWorkspaceFiles({
872
+ workspacePath: request.workspacePath,
873
+ currentDirectory: absolutePath,
874
+ files: request.files
875
+ });
876
+ continue;
877
+ }
878
+ if (!directoryEntry.isFile()) continue;
879
+ request.files.push(node_path.default.relative(request.workspacePath, absolutePath).replace(/\\/g, "/"));
880
+ }
881
+ }
882
+ async function appendWorkingTreeEntry(request) {
883
+ if (!await runner.fileExists({ filePath: request.absolutePath })) return request.entries;
884
+ const lastEntry = request.entries.at(-1);
885
+ const lastTouchingEntry = request.entries.filter((entry) => entry.touchesFile && !entry.isWorkingTree).at(-1);
886
+ if (lastEntry?.isWorkingTree) return request.entries;
887
+ if (lastTouchingEntry) {
888
+ if (await (0, node_fs_promises.readFile)(request.absolutePath, "utf8") === await request.adapter.showFileAtRevision({
889
+ workspacePath: request.workspacePath,
890
+ revset: lastTouchingEntry.revision,
891
+ filePath: lastTouchingEntry.filePath || request.relativePath
892
+ }) && (lastTouchingEntry.filePath || request.relativePath) === request.relativePath) return request.entries;
893
+ }
894
+ const now = /* @__PURE__ */ new Date();
895
+ return [...request.entries, {
896
+ id: "working-tree",
897
+ revision: "WORKTREE",
898
+ shortRevision: "Current",
899
+ changeId: void 0,
900
+ authorDate: now.toISOString(),
901
+ authorName: "",
902
+ description: "Working tree",
903
+ isWorkingTree: true,
904
+ touchesFile: true,
905
+ timestamp: now.getTime(),
906
+ filePath: request.relativePath
907
+ }];
908
+ }
909
+ function composeSnapshotEntries(request) {
910
+ if (!request.loadedChangeIds.size) return request.revisionEntries;
911
+ const snapshotEntriesByChangeId = request.snapshotEntries.reduce((groups, entry) => {
912
+ if (!entry.changeId) return groups;
913
+ const existing = groups.get(entry.changeId) || [];
914
+ existing.push(entry);
915
+ groups.set(entry.changeId, existing);
916
+ return groups;
917
+ }, /* @__PURE__ */ new Map());
918
+ return request.revisionEntries.flatMap((entry) => {
919
+ if (entry.isWorkingTree || !entry.touchesFile || !entry.changeId || !request.loadedChangeIds.has(entry.changeId)) return [entry];
920
+ return snapshotEntriesByChangeId.get(entry.changeId) || [entry];
921
+ });
922
+ }
923
+ async function getJjSnapshotPreview(request) {
924
+ const sourceEntries = getEntriesForSource({
925
+ session: request.session,
926
+ comparisonSource: "snapshot"
927
+ });
928
+ const normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));
929
+ const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));
930
+ const entry = sourceEntries[normalizedToIndex];
931
+ if (!entry) return createEmptyPreview({
932
+ index: normalizedToIndex,
933
+ fromIndex: normalizedFromIndex,
934
+ toIndex: normalizedToIndex,
935
+ comparisonSource: "snapshot",
936
+ title: "No revision selected"
937
+ });
938
+ const afterPath = await resolveEntryFilePath({
939
+ session: request.session,
940
+ entry,
941
+ entryIndex: normalizedToIndex
942
+ });
943
+ const previousEntryIndex = normalizedFromIndex === normalizedToIndex ? normalizedToIndex - 1 : normalizedFromIndex;
944
+ const previousEntry = previousEntryIndex >= 0 ? sourceEntries[previousEntryIndex] : void 0;
945
+ const previousPath = previousEntry ? await resolveEntryFilePath({
946
+ session: request.session,
947
+ entry: previousEntry,
948
+ entryIndex: previousEntryIndex
949
+ }) : entry.isWorkingTree ? request.session.relativePath : await resolvePreviousPathAcrossRevision({
950
+ session: request.session,
951
+ entry,
952
+ currentPath: afterPath
953
+ });
954
+ return {
955
+ ...buildDiffPreview({
956
+ index: normalizedToIndex,
957
+ previousEntry,
958
+ currentEntry: entry,
959
+ beforeText: previousEntry ? await getRevisionContent({
960
+ session: request.session,
961
+ entry: previousEntry,
962
+ entryIndex: previousEntryIndex
963
+ }) : entry.isWorkingTree ? "" : await getContentForRevset({
964
+ session: request.session,
965
+ revset: `${entry.revision}-`,
966
+ filePath: previousPath
967
+ }),
968
+ afterText: await getRevisionContent({
969
+ session: request.session,
970
+ entry,
971
+ entryIndex: normalizedToIndex
972
+ }),
973
+ fromIndex: normalizedFromIndex,
974
+ toIndex: normalizedToIndex,
975
+ beforePath: previousPath,
976
+ afterPath,
977
+ comparisonSource: "snapshot"
978
+ }),
979
+ title: entry.isWorkingTree ? `Snapshot @ ${entry.shortRevision}` : `Snapshot ${entry.shortRevision}`
980
+ };
981
+ }
982
+ async function getRevisionContent(request) {
983
+ const resolvedPath = request.entry.isWorkingTree ? request.session.relativePath : await resolveEntryFilePath(request);
984
+ const cacheKey = `${request.entry.id}:${resolvedPath}`;
985
+ const cached = request.session.contentCache.get(cacheKey);
986
+ if (cached !== void 0) return cached;
987
+ const content = request.entry.isWorkingTree ? await (0, node_fs_promises.readFile)(request.session.absolutePath, "utf8") : await request.session.adapter.showFileAtRevision({
988
+ workspacePath: request.session.workspacePath,
989
+ revset: request.entry.revision,
990
+ filePath: resolvedPath
991
+ });
992
+ request.session.contentCache.set(cacheKey, content);
993
+ return content;
994
+ }
995
+ async function ensureEntryFilePath(request) {
996
+ const targetEntry = request.session.entries[request.entryIndex];
997
+ if (!targetEntry || targetEntry.filePath || targetEntry.isWorkingTree) return;
998
+ let knownIndex = -1;
999
+ for (let index = request.entryIndex + 1; index < request.session.entries.length; index += 1) if (request.session.entries[index]?.filePath) {
1000
+ knownIndex = index;
1001
+ break;
1002
+ }
1003
+ if (knownIndex < 0) {
1004
+ targetEntry.filePath = request.session.relativePath;
1005
+ return;
1006
+ }
1007
+ let currentPath = request.session.entries[knownIndex].filePath || request.session.relativePath;
1008
+ for (let index = knownIndex; index > request.entryIndex; index -= 1) {
1009
+ const currentEntry = request.session.entries[index];
1010
+ const previousEntry = request.session.entries[index - 1];
1011
+ if (!previousEntry) break;
1012
+ if (!previousEntry.filePath) {
1013
+ let previousPath = currentPath;
1014
+ if (currentEntry.touchesFile && !currentEntry.isWorkingTree) previousPath = await resolvePreviousPathAcrossRevision({
1015
+ session: request.session,
1016
+ entry: currentEntry,
1017
+ currentPath
1018
+ });
1019
+ previousEntry.filePath = previousPath;
1020
+ }
1021
+ currentPath = previousEntry.filePath || currentPath;
1022
+ }
1023
+ }
1024
+ }
1025
+ function normalizeTimelinePreferences(preferences) {
1026
+ if (!preferences) return { ...DEFAULT_TIMELINE_PREFERENCES };
1027
+ return {
1028
+ sidebarWidth: typeof preferences.sidebarWidth === "number" ? preferences.sidebarWidth : DEFAULT_TIMELINE_PREFERENCES.sidebarWidth,
1029
+ sidebarCollapsed: preferences.sidebarCollapsed === true,
1030
+ timelinePaneHeight: typeof preferences.timelinePaneHeight === "number" ? preferences.timelinePaneHeight : DEFAULT_TIMELINE_PREFERENCES.timelinePaneHeight,
1031
+ timelinePaneCollapsed: preferences.timelinePaneCollapsed === true,
1032
+ layoutMode: preferences.layoutMode === "unified" ? "unified" : DEFAULT_TIMELINE_PREFERENCES.layoutMode,
1033
+ contentMode: preferences.contentMode === "full" ? "full" : DEFAULT_TIMELINE_PREFERENCES.contentMode,
1034
+ comparisonMode: preferences.comparisonMode === "step" ? "step" : DEFAULT_TIMELINE_PREFERENCES.comparisonMode,
1035
+ comparisonSource: preferences.comparisonSource === "snapshot" ? "snapshot" : DEFAULT_TIMELINE_PREFERENCES.comparisonSource,
1036
+ showIntermediateRevisions: preferences.showIntermediateRevisions === true,
1037
+ preset: preferences.preset === "7d" || preferences.preset === "30d" || preferences.preset === "90d" || preferences.preset === "all" || preferences.preset === "year" ? preferences.preset : DEFAULT_TIMELINE_PREFERENCES.preset,
1038
+ customRevset: typeof preferences.customRevset === "string" ? preferences.customRevset.trim() : "",
1039
+ themePreference: preferences.themePreference === "light" || preferences.themePreference === "dark" ? preferences.themePreference : DEFAULT_TIMELINE_PREFERENCES.themePreference,
1040
+ heatmapOpen: preferences.heatmapOpen === true,
1041
+ lineDiffType: preferences.lineDiffType === "word" || preferences.lineDiffType === "char" || preferences.lineDiffType === "none" || preferences.lineDiffType === "word-alt" ? preferences.lineDiffType : DEFAULT_TIMELINE_PREFERENCES.lineDiffType
1042
+ };
1043
+ }
1044
+ function createEmptyPreview(args) {
1045
+ return {
1046
+ index: args.index,
1047
+ title: args.title,
1048
+ subtitle: "",
1049
+ diffCount: 0,
1050
+ additions: 0,
1051
+ deletions: 0,
1052
+ hunkCount: 0,
1053
+ hasChanges: false,
1054
+ fromIndex: args.fromIndex,
1055
+ toIndex: args.toIndex,
1056
+ comparisonSource: args.comparisonSource,
1057
+ beforePath: "",
1058
+ afterPath: "",
1059
+ beforeText: "",
1060
+ afterText: "",
1061
+ nonTextualDetails: []
1062
+ };
1063
+ }
1064
+ function buildDiffPreview(args) {
1065
+ const stats = require_diff_stats.computeDiffStats(args.beforeText, args.afterText);
1066
+ const title = args.previousEntry ? `${args.previousEntry.shortRevision} -> ${args.currentEntry.shortRevision}` : `Initial revision -> ${args.currentEntry.shortRevision}`;
1067
+ const subtitle = args.currentEntry.isWorkingTree ? "Working tree" : `${formatEntryDateTime(args.currentEntry.authorDate)} · ${args.currentEntry.description}`;
1068
+ return {
1069
+ index: args.index,
1070
+ title,
1071
+ subtitle,
1072
+ diffCount: 0,
1073
+ additions: stats.additions,
1074
+ deletions: stats.deletions,
1075
+ hunkCount: stats.hunkCount,
1076
+ hasChanges: stats.hasChanges,
1077
+ fromIndex: args.fromIndex,
1078
+ toIndex: args.toIndex,
1079
+ comparisonSource: args.comparisonSource,
1080
+ beforePath: args.beforePath,
1081
+ afterPath: args.afterPath,
1082
+ beforeText: args.beforeText,
1083
+ afterText: args.afterText,
1084
+ nonTextualDetails: stats.hasChanges ? [] : require_non_textual_details.buildNonTextualDetails({
1085
+ beforeText: args.beforeText,
1086
+ afterText: args.afterText,
1087
+ beforePath: args.beforePath,
1088
+ afterPath: args.afterPath,
1089
+ isWorkingTree: args.currentEntry.isWorkingTree
1090
+ })
1091
+ };
1092
+ }
1093
+ function mergeTimelineEntries(args) {
1094
+ const touchingByRevision = new Map(args.fileEntries.map((entry) => [entry.revision, entry]));
1095
+ const repoIndexes = args.fileEntries.map((entry) => args.repositoryEntries.findIndex((candidate) => candidate.revision === entry.revision)).filter((index) => index >= 0);
1096
+ if (!repoIndexes.length) return args.fileEntries;
1097
+ const startIndex = Math.min(...repoIndexes);
1098
+ const endIndex = Math.max(...repoIndexes);
1099
+ const merged = args.repositoryEntries.slice(startIndex, endIndex + 1).map((entry) => touchingByRevision.get(entry.revision) || entry);
1100
+ for (const entry of args.fileEntries) if (!merged.some((candidate) => candidate.revision === entry.revision)) merged.push(entry);
1101
+ return merged.toSorted((left, right) => left.timestamp - right.timestamp || left.revision.localeCompare(right.revision));
1102
+ }
1103
+ function dedupeAdjacentTimelineEntries(entries) {
1104
+ return entries.reduce((deduped, entry) => {
1105
+ const previousEntry = deduped.at(-1);
1106
+ if (!previousEntry?.changeId || previousEntry.changeId !== entry.changeId) {
1107
+ deduped.push(entry);
1108
+ return deduped;
1109
+ }
1110
+ if (previousEntry.touchesFile && entry.touchesFile) {
1111
+ deduped.push(entry);
1112
+ return deduped;
1113
+ }
1114
+ if (!previousEntry.touchesFile && entry.touchesFile) deduped[deduped.length - 1] = entry;
1115
+ return deduped;
1116
+ }, []);
1117
+ }
1118
+ function formatEntryMonthLabel(authorDate) {
1119
+ const date = new Date(authorDate);
1120
+ if (Number.isNaN(date.getTime())) return "Unknown month";
1121
+ return new Intl.DateTimeFormat("en", { month: "long" }).format(date);
1122
+ }
1123
+ function formatEntryShortDate(authorDate) {
1124
+ const date = new Date(authorDate);
1125
+ if (Number.isNaN(date.getTime())) return "Unknown date";
1126
+ return new Intl.DateTimeFormat("en", {
1127
+ month: "short",
1128
+ day: "numeric",
1129
+ year: "numeric"
1130
+ }).format(date);
1131
+ }
1132
+ function formatRelativeTime(timestamp) {
1133
+ const deltaSeconds = Math.round((timestamp - Date.now()) / 1e3);
1134
+ const formatter = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
1135
+ for (const [unit, amount] of [
1136
+ ["day", 86400],
1137
+ ["hour", 3600],
1138
+ ["minute", 60]
1139
+ ]) if (Math.abs(deltaSeconds) >= amount || unit === "minute") return formatter.format(Math.round(deltaSeconds / amount), unit);
1140
+ return formatter.format(deltaSeconds, "second");
1141
+ }
1142
+ function formatEntryDateTime(authorDate) {
1143
+ const date = new Date(authorDate);
1144
+ if (Number.isNaN(date.getTime())) return "Unknown time";
1145
+ return date.toLocaleString();
1146
+ }
1147
+ function isAbortError(error) {
1148
+ return error instanceof Error && (error.name === "AbortError" || /aborted/i.test(error.message));
1149
+ }
1150
+ //#endregion
1151
+ exports.createTimelineService = createTimelineService;
1152
+ exports.normalizeTimelinePreferences = normalizeTimelinePreferences;
1153
+
1154
+ //# sourceMappingURL=timeline-service.cjs.map